Skip to content

Commit 466e6cc

Browse files
authored
refactor+fix: configurable deployer / lib regularizer fix (#351)
deployer's job template file is hard-coded, which makes it hard to use different template file at deployment time. Using different different template file is useful when underlying infrastructure is different (e.g., k8s vs knative). To support that, template folder and file is fed as config variables. Also, deployer's config info is fed as command argument, which is cumbersome. So, the config parsing part is refactored such that the info is fed as a configuration file. During the testing of deployer change, a bug in the library is identified. The fix for it is added here too. Finally, the local dns configuration in flame.sh is updated so that it can be done correctly across different linux distributions (e.g., archlinux and ubuntu). The tests for flame.sh are under archlinux and ubuntu.
1 parent 6532a3b commit 466e6cc

File tree

12 files changed

+303
-215
lines changed

12 files changed

+303
-215
lines changed

cmd/deployer/app/resource_handler.go

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,17 @@ import (
3434
"google.golang.org/grpc/credentials/insecure"
3535

3636
"github.com/cisco-open/flame/cmd/deployer/app/deployer"
37+
"github.com/cisco-open/flame/cmd/deployer/config"
3738
"github.com/cisco-open/flame/pkg/openapi"
3839
pbNotify "github.com/cisco-open/flame/pkg/proto/notification"
3940
"github.com/cisco-open/flame/pkg/restapi"
4041
"github.com/cisco-open/flame/pkg/util"
4142
)
4243

4344
const (
44-
deploymentDirPath = "/" + util.ProjectName + "/deployment"
4545
deploymentTemplateDir = "templates"
4646

47-
jobTemplateDirPath = "/" + util.ProjectName + "/template"
48-
jobDeploymentFilePrefix = "job-agent"
49-
jobTemplatePath = jobTemplateDirPath + "/" + jobDeploymentFilePrefix + ".yaml.mustache"
50-
k8sShortLabelLength = 12
47+
k8sShortLabelLength = 12
5148
)
5249

5350
var (
@@ -63,13 +60,17 @@ type resourceHandler struct {
6360
namespace string
6461
dplyr deployer.Deployer
6562

63+
// variables for job templates
64+
jobTemplateDirPath string
65+
jobTemplatePath string
66+
deploymentDirPath string
67+
6668
stream pbNotify.DeployEventRoute_GetDeployEventClient
6769

6870
grpcDialOpt grpc.DialOption
6971
}
7072

71-
func NewResourceHandler(apiserverEp string, notifierEp string, computeSpec openapi.ComputeSpec,
72-
platform string, namespace string, bInsecure bool, bPlain bool) *resourceHandler {
73+
func NewResourceHandler(cfg *config.Config, computeSpec openapi.ComputeSpec, bInsecure bool, bPlain bool) *resourceHandler {
7374
var grpcDialOpt grpc.DialOption
7475

7576
if bPlain {
@@ -85,21 +86,28 @@ func NewResourceHandler(apiserverEp string, notifierEp string, computeSpec opena
8586
grpcDialOpt = grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))
8687
}
8788

88-
dplyr, err := deployer.NewDeployer(platform)
89+
dplyr, err := deployer.NewDeployer(cfg.Platform)
8990
if err != nil {
9091
zap.S().Errorf("failed to obtain a job deployer: %v", err)
9192
return nil
9293
}
9394

95+
parentDir := filepath.Dir(cfg.JobTemplate.Folder)
96+
deploymentDirPath := filepath.Join(parentDir, "deployment")
97+
9498
rHandler := &resourceHandler{
95-
apiserverEp: apiserverEp,
96-
notifierEp: notifierEp,
99+
apiserverEp: cfg.Apiserver,
100+
notifierEp: cfg.Notifier,
97101
spec: computeSpec,
98102

99-
platform: platform,
100-
namespace: namespace,
103+
platform: cfg.Platform,
104+
namespace: cfg.Namespace,
101105
dplyr: dplyr,
102106

107+
jobTemplateDirPath: cfg.JobTemplate.Folder,
108+
jobTemplatePath: filepath.Join(cfg.JobTemplate.Folder, cfg.JobTemplate.File),
109+
deploymentDirPath: deploymentDirPath,
110+
103111
grpcDialOpt: grpcDialOpt,
104112
}
105113

@@ -249,7 +257,7 @@ func (r *resourceHandler) revokeResource(jobId string) (err error) {
249257
}
250258
taskStatuses[taskId] = openapi.AGENT_REVOKE_SUCCESS
251259
// 2.delete all the task resource specification files
252-
deploymentChartPath := filepath.Join(deploymentDirPath, jobId, taskId)
260+
deploymentChartPath := filepath.Join(r.deploymentDirPath, jobId, taskId)
253261
removeErr := os.RemoveAll(deploymentChartPath)
254262
if removeErr != nil {
255263
zap.S().Errorf("Errors occurred deleting specification files: %v", removeErr)
@@ -323,11 +331,14 @@ func (r *resourceHandler) deployResources(deploymentConfig openapi.DeploymentCon
323331
errMsg := fmt.Sprintf("failed to initialize a job deployer: %v", err)
324332
return fmt.Errorf(errMsg)
325333
}
334+
326335
agentStatuses := map[string]openapi.AgentState{}
327336
defer r.postDeploymentStatus(deploymentConfig.JobId, agentStatuses)
337+
328338
for taskId := range deploymentConfig.AgentKVs {
329-
deploymentChartPath := filepath.Join(deploymentDirPath, deploymentConfig.JobId, taskId)
339+
deploymentChartPath := filepath.Join(r.deploymentDirPath, deploymentConfig.JobId, taskId)
330340
targetTemplateDirPath := filepath.Join(deploymentChartPath, deploymentTemplateDir)
341+
331342
if makeErr := os.MkdirAll(targetTemplateDirPath, util.FilePerm0644); makeErr != nil {
332343
errMsg := fmt.Sprintf("failed to create a deployment template folder: %v", makeErr)
333344
err = fmt.Errorf("%v; %v", err, errMsg)
@@ -336,37 +347,38 @@ func (r *resourceHandler) deployResources(deploymentConfig openapi.DeploymentCon
336347
}
337348

338349
// Copy helm chart files to destination folder
339-
copyErr := copyHelmCharts(helmChartFiles, jobTemplateDirPath, deploymentChartPath)
350+
copyErr := copyHelmCharts(helmChartFiles, r.jobTemplateDirPath, deploymentChartPath)
340351
if copyErr != nil {
341352
err = fmt.Errorf("%v; %v", err, copyErr)
342353
agentStatuses[taskId] = openapi.AGENT_DEPLOY_FAILED
343354
continue
344355
}
345356

346-
taskKey := deploymentConfig.AgentKVs[taskId]
347-
348357
ctx := map[string]string{
349358
"imageLoc": deploymentConfig.ImageLoc,
350359
"taskId": taskId,
351-
"taskKey": taskKey,
360+
"taskKey": deploymentConfig.AgentKVs[taskId],
352361
}
353-
rendered, renderErr := mustache.RenderFile(jobTemplatePath, &ctx)
362+
363+
rendered, renderErr := mustache.RenderFile(r.jobTemplatePath, &ctx)
354364
if renderErr != nil {
355365
errMsg := fmt.Sprintf("failed to render a template for task %s: %v", taskId, renderErr)
356366
err = fmt.Errorf("%v; %v", err, errMsg)
357367
agentStatuses[taskId] = openapi.AGENT_DEPLOY_FAILED
358368
continue
359369
}
360370

361-
deploymentFileName := fmt.Sprintf("%s-%s.yaml", jobDeploymentFilePrefix, taskId)
371+
deploymentFileName := fmt.Sprintf("task-%s.yaml", taskId)
362372
deploymentFilePath := filepath.Join(targetTemplateDirPath, deploymentFileName)
373+
363374
writeErr := os.WriteFile(deploymentFilePath, []byte(rendered), util.FilePerm0644)
364375
if writeErr != nil {
365376
errMsg := fmt.Sprintf("failed to write a job rosource spec %s: %v", taskId, writeErr)
366377
err = fmt.Errorf("%v; %v", err, errMsg)
367378
agentStatuses[taskId] = openapi.AGENT_DEPLOY_FAILED
368379
continue
369380
}
381+
370382
//using short id of task as label name does not support more than 35 characters
371383
installErr := r.dplyr.Install("job-"+deploymentConfig.JobId+"-"+taskId[:k8sShortLabelLength], deploymentChartPath)
372384
if installErr != nil {
@@ -375,6 +387,7 @@ func (r *resourceHandler) deployResources(deploymentConfig openapi.DeploymentCon
375387
agentStatuses[taskId] = openapi.AGENT_DEPLOY_FAILED
376388
continue
377389
}
390+
378391
agentStatuses[taskId] = openapi.AGENT_DEPLOY_SUCCESS
379392
}
380393

cmd/deployer/cmd/root.go

Lines changed: 63 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -18,149 +18,89 @@ package cmd
1818

1919
import (
2020
"fmt"
21-
"strings"
21+
"path/filepath"
2222

2323
"github.com/spf13/cobra"
24+
"go.uber.org/zap"
2425

2526
"github.com/cisco-open/flame/cmd/deployer/app"
27+
"github.com/cisco-open/flame/cmd/deployer/config"
2628
"github.com/cisco-open/flame/pkg/openapi"
2729
"github.com/cisco-open/flame/pkg/util"
2830
)
2931

3032
const (
31-
argApiserver = "apiserver"
32-
argNotifier = "notifier"
33-
argAdminId = "adminid"
34-
argRegion = "region"
35-
argComputeId = "computeid"
36-
argApiKey = "apikey"
37-
argPlatform = "platform"
38-
argNamespace = "namespace"
39-
4033
optionInsecure = "insecure"
4134
optionPlain = "plain"
4235
)
4336

44-
var rootCmd = &cobra.Command{
45-
Use: util.Deployer,
46-
Short: util.ProjectName + " Deployer",
47-
RunE: func(cmd *cobra.Command, args []string) error {
48-
flags := cmd.Flags()
49-
50-
apiserver, err := flags.GetString(argApiserver)
51-
if err != nil {
52-
return err
53-
}
54-
if len(strings.Split(apiserver, ":")) != util.NumTokensInRestEndpoint {
55-
return fmt.Errorf("incorrect format for apiserver endpoint: %s", apiserver)
56-
}
57-
58-
notifier, err := flags.GetString(argNotifier)
59-
if err != nil {
60-
return err
61-
}
62-
if len(strings.Split(notifier, ":")) != util.NumTokensInEndpoint {
63-
return fmt.Errorf("incorrect format for notifier endpoint: %s", notifier)
64-
}
65-
66-
adminId, err := flags.GetString(argAdminId)
67-
if err != nil {
68-
return err
69-
}
70-
71-
region, err := flags.GetString(argRegion)
72-
if err != nil {
73-
return err
74-
}
75-
76-
computeId, err := flags.GetString(argComputeId)
77-
if err != nil {
78-
return err
79-
}
80-
81-
apikey, err := flags.GetString(argApiKey)
82-
if err != nil {
83-
return err
84-
}
85-
86-
platform, err := flags.GetString(argPlatform)
87-
if err != nil {
88-
return err
89-
}
90-
91-
namespace, err := flags.GetString(argNamespace)
92-
if err != nil {
93-
return err
94-
}
95-
96-
bInsecure, _ := flags.GetBool(optionInsecure)
97-
bPlain, _ := flags.GetBool(optionPlain)
98-
99-
if bInsecure && bPlain {
100-
err = fmt.Errorf("options --%s and --%s are incompatible; enable one of them", optionInsecure, optionPlain)
101-
return err
102-
}
103-
104-
computeSpec := openapi.ComputeSpec{
105-
AdminId: adminId,
106-
Region: region,
107-
ComputeId: computeId,
108-
ApiKey: apikey,
109-
}
110-
111-
compute, err := app.NewCompute(apiserver, computeSpec, bInsecure, bPlain)
112-
if err != nil {
113-
return err
114-
}
115-
116-
err = compute.RegisterNewCompute()
117-
if err != nil {
118-
err = fmt.Errorf("unable to register new compute with controller: %s", err)
119-
return err
120-
}
121-
122-
resoureHandler := app.NewResourceHandler(apiserver, notifier, computeSpec, platform, namespace, bInsecure, bPlain)
123-
resoureHandler.Start()
124-
125-
select {}
126-
},
127-
}
37+
var (
38+
cfgFile string
39+
cfg *config.Config
40+
41+
rootCmd = &cobra.Command{
42+
Use: util.Deployer,
43+
Short: util.ProjectName + " Deployer",
44+
RunE: func(cmd *cobra.Command, args []string) error {
45+
flags := cmd.Flags()
46+
47+
bInsecure, _ := flags.GetBool(optionInsecure)
48+
bPlain, _ := flags.GetBool(optionPlain)
49+
50+
if bInsecure && bPlain {
51+
err := fmt.Errorf("options --%s and --%s are incompatible; enable one of them",
52+
optionInsecure, optionPlain)
53+
return err
54+
}
55+
56+
computeSpec := openapi.ComputeSpec{
57+
AdminId: cfg.AdminId,
58+
Region: cfg.Region,
59+
ComputeId: cfg.ComputeId,
60+
ApiKey: cfg.Apikey,
61+
}
62+
63+
compute, err := app.NewCompute(cfg.Apiserver, computeSpec, bInsecure, bPlain)
64+
if err != nil {
65+
return err
66+
}
67+
68+
err = compute.RegisterNewCompute()
69+
if err != nil {
70+
err = fmt.Errorf("unable to register new compute with controller: %s", err)
71+
return err
72+
}
73+
74+
resoureHandler := app.NewResourceHandler(cfg, computeSpec, bInsecure, bPlain)
75+
resoureHandler.Start()
76+
77+
select {}
78+
},
79+
}
80+
)
12881

12982
func init() {
130-
defaultApiServerEp := fmt.Sprintf("http://0.0.0.0:%d", util.ApiServerRestApiPort)
131-
rootCmd.Flags().StringP(argApiserver, "a", defaultApiServerEp, "API server endpoint")
132-
rootCmd.MarkFlagRequired(argApiserver)
133-
134-
defaultNotifierEp := fmt.Sprintf("0.0.0.0:%d", util.NotifierGrpcPort)
135-
rootCmd.Flags().StringP(argNotifier, "n", defaultNotifierEp, "Notifier endpoint")
136-
rootCmd.MarkFlagRequired(argNotifier)
137-
138-
defaultAdminId := "admin"
139-
rootCmd.Flags().StringP(argAdminId, "d", defaultAdminId, "unique admin id")
140-
rootCmd.MarkFlagRequired(argAdminId)
141-
142-
defaultRegion := "region"
143-
rootCmd.Flags().StringP(argRegion, "r", defaultRegion, "region name")
144-
rootCmd.MarkFlagRequired(argRegion)
83+
cobra.OnInitialize(initConfig)
14584

146-
defaultComputeId := "compute"
147-
rootCmd.Flags().StringP(argComputeId, "c", defaultComputeId, "unique compute id")
148-
rootCmd.MarkFlagRequired(argComputeId)
85+
usage := "config file (default: /etc/flame/deployer.yaml)"
86+
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", usage)
87+
rootCmd.CompletionOptions.DisableDefaultCmd = true
14988

150-
defaultApiKey := "apiKey"
151-
rootCmd.Flags().StringP(argApiKey, "k", defaultApiKey, "unique apikey")
152-
rootCmd.MarkFlagRequired(argApiKey)
89+
rootCmd.PersistentFlags().Bool(optionInsecure, false, "Allow insecure connection")
90+
rootCmd.PersistentFlags().Bool(optionPlain, false, "Allow unencrypted connection")
91+
}
15392

154-
defaultPlatform := "k8s"
155-
rootCmd.Flags().StringP(argPlatform, "p", defaultPlatform, "compute platform")
156-
rootCmd.MarkFlagRequired(argPlatform)
93+
func initConfig() {
94+
if cfgFile == "" {
95+
cfgFile = filepath.Join("/etc/flame/deployer.yaml")
96+
}
15797

158-
defaultNamespace := "flame"
159-
rootCmd.Flags().StringP(argNamespace, "s", defaultNamespace, "compute namespace")
160-
rootCmd.MarkFlagRequired(argNamespace)
98+
var err error
16199

162-
rootCmd.PersistentFlags().Bool(optionInsecure, false, "Allow insecure connection")
163-
rootCmd.PersistentFlags().Bool(optionPlain, false, "Allow unencrypted connection")
100+
cfg, err = config.LoadConfig(cfgFile)
101+
if err != nil {
102+
zap.S().Fatalf("Failed to load config %s: %v", cfgFile, err)
103+
}
164104
}
165105

166106
func Execute() error {

0 commit comments

Comments
 (0)