From 8ef2d75fcb53f2cbfeac89cda4814af6bc88fb96 Mon Sep 17 00:00:00 2001 From: Milos Pejanovic Date: Tue, 3 Mar 2020 15:23:10 +0100 Subject: [PATCH] Refactor service deployment loading logic --- cmd/actions/deploy.go | 10 ++-- configurd.go | 112 +++++++++++++++++++++++++++++++++++++++++- helm.go | 72 ++++++++++----------------- 3 files changed, 143 insertions(+), 51 deletions(-) diff --git a/cmd/actions/deploy.go b/cmd/actions/deploy.go index b65f6d6..b55718b 100644 --- a/cmd/actions/deploy.go +++ b/cmd/actions/deploy.go @@ -28,14 +28,14 @@ var ( ) func Deploy(namespace, deployment, tag string) { - sds, err := cnf.ServiceDeployments(cwdir, namespace, deployment) - if err != nil { - log.Fatalf("could not deploy: %v output:\n%v", deployment, err) + sds := cnf.GetServiceDeployments(namespace, deployment) + if len(sds) == 0 { + log.Fatalf("could not find any service deployments for namespace: %v and deployment: %v", namespace, deployment) } if flagBuild { for _, serviceDeployment := range sds { - Build(serviceDeployment.ServiceName, FlagTag) + Build(serviceDeployment.ServiceName, tag) } } - cnf.Deploy(sds, cwdir, tag) + cnf.Deploy(sds, cwdir) } diff --git a/configurd.go b/configurd.go index 162d839..b9b0d34 100644 --- a/configurd.go +++ b/configurd.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "log" "os" "path" "path/filepath" @@ -25,10 +26,20 @@ var ( ErrServiceNotFound = errors.New("service not found") ) +type Deployment struct { + name string + serviceDeployments []ServiceDeployment +} + +type Namespace struct { + name string + deployments []Deployment +} + type Configurd struct { Services []Service Templates []string - Namespaces []string + Namespaces []Namespace } func New(dir string) (Configurd, error) { @@ -59,9 +70,88 @@ func New(dir string) (Configurd, error) { return Configurd{}, err } + c.Namespaces, err = loadNamespaces(c, dir) + + if err != nil { + return Configurd{}, err + } + return c, nil } +func loadNamespaces(c Configurd, basePath string) ([]Namespace, error) { + var nss []Namespace + namespaceDir := path.Join(basePath, defaultNamespaceDir) + err := filepath.Walk(namespaceDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() && path != namespaceDir { + ds, err := loadDeployments(c, info.Name()) + if err != nil { + return err + } + ns := Namespace{ + name: info.Name(), + deployments: ds, + } + nss = append(nss, ns) + } + return nil + }) + return nss, err +} + +func loadDeployments(c Configurd, namespace string) ([]Deployment, error) { + var ds []Deployment + err := filepath.Walk(path.Join(defaultNamespaceDir, namespace), func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() && (strings.HasSuffix(path, defaultConfigFileExt)) { + var name = info.Name()[0 : len(info.Name())-len(filepath.Ext(info.Name()))] + sds, err := loadServiceDeployments(c, namespace, name) + if err != nil { + return err + } + d := Deployment{ + name: name, + serviceDeployments: sds, + } + ds = append(ds, d) + } + return nil + }) + return ds, err +} + +func loadServiceDeployments(c Configurd, namespace, deployment string) ([]ServiceDeployment, error) { + path := path.Join(defaultNamespaceDir, namespace, deployment+defaultConfigFileExt) + file, err := os.Open(path) + defer file.Close() + if err != nil { + return []ServiceDeployment{}, err + } + + var wrapper struct { + ServiceDeployments []ServiceDeployment `yaml:"services"` + } + if err := yaml.NewDecoder(file).Decode(&wrapper); err != nil { + return []ServiceDeployment{}, fmt.Errorf("could not decode service deployment: %w", err) + } + + for i, sd := range wrapper.ServiceDeployments { + svc, err := c.Service(sd.ServiceName) + if err != nil { + log.Fatal(err) + } + wrapper.ServiceDeployments[i].chart = svc.Chart + wrapper.ServiceDeployments[i].namespace = namespace + wrapper.ServiceDeployments[i].deployment = deployment + } + return wrapper.ServiceDeployments, nil +} + func (c Configurd) Service(name string) (Service, error) { for _, svc := range c.Services { if svc.Name == name { @@ -71,6 +161,26 @@ func (c Configurd) Service(name string) (Service, error) { return Service{}, ErrServiceNotFound } +func (c Configurd) GetServiceDeployments(namespace, deployment string) []ServiceDeployment { + var sds []ServiceDeployment + for _, sd := range c.serviceDeployments() { + if sd.namespace == namespace && sd.deployment == deployment { + sds = append(sds, sd) + } + } + return sds +} + +func (c Configurd) serviceDeployments() []ServiceDeployment { + var sds []ServiceDeployment + for _, ns := range c.Namespaces { + for _, d := range ns.deployments { + sds = append(sds, d.serviceDeployments...) + } + } + return sds +} + func loadService(reader io.Reader) (Service, error) { var wrapper struct { Service Service `yaml:"service"` diff --git a/helm.go b/helm.go index b793320..d317e72 100644 --- a/helm.go +++ b/helm.go @@ -16,8 +16,9 @@ import ( type ServiceDeployment struct { ServiceName string `yaml:"service"` Overrides interface{} - chart string namespace string + deployment string + chart string } func generateYaml(path string, data interface{}) error { @@ -37,7 +38,7 @@ func generateYaml(path string, data interface{}) error { return nil } -func generate(sd ServiceDeployment, outputDir, chartPath, tag string) error { +func generate(sd ServiceDeployment, outputDir, chartPath string) error { dir := path.Join(outputDir, sd.ServiceName) if err := os.MkdirAll(dir, 0744); err != nil { return fmt.Errorf("could not create output dir: %w", err) @@ -69,7 +70,27 @@ func generate(sd ServiceDeployment, outputDir, chartPath, tag string) error { return nil } -func (c Configurd) Deploy(sds []ServiceDeployment, basePath, tag string) (string, error) { +func helmInstall(serviceName, namespace, basePath string) error { + chartPath := path.Join(basePath, defaultDeploymentDir, serviceName) + cmdArgs := []string{ + "install", serviceName, chartPath, + "-f", path.Join(chartPath, defaultOverridesFile), + "-n", namespace, + "--set", "fullnameOverride=" + serviceName, + } + cmd := exec.Command("helm", cmdArgs...) + + out, err := cmd.CombinedOutput() + output := strings.Replace(string(out), "\n", "\n\t", -1) + + log.Print(string(out)) + if err != nil { + return fmt.Errorf("could not install a helm chart for service %v output: \n%v", serviceName, output) + } + return nil +} + +func (c Configurd) Deploy(sds []ServiceDeployment, basePath string) (string, error) { if err := os.RemoveAll(defaultDeploymentDir); err != nil { return "", fmt.Errorf("could not clean deployment directory: %w", err) } @@ -78,54 +99,15 @@ func (c Configurd) Deploy(sds []ServiceDeployment, basePath, tag string) (string return "", fmt.Errorf("could not create a deployments directory: %w", err) } for _, sd := range sds { - err := generate(sd, defaultDeploymentDir, path.Join(defaultChartDir, sd.chart), tag) + err := generate(sd, defaultDeploymentDir, path.Join(defaultChartDir, sd.chart)) if err != nil { return "", err } - - // helm install - chartPath := path.Join(basePath, defaultDeploymentDir, sd.ServiceName) - cmdArgs := []string{ - "install", sd.ServiceName, chartPath, - "-f", path.Join(chartPath, defaultOverridesFile), - "-n", sd.namespace, - "--set", "fullnameOverride=" + sd.ServiceName, - } - cmd := exec.Command("helm", cmdArgs...) - - out, err := cmd.CombinedOutput() - output := strings.Replace(string(out), "\n", "\n\t", -1) - - log.Print(string(out)) + err = helmInstall(sd.ServiceName, sd.namespace, basePath) if err != nil { - return "", fmt.Errorf("could not install a helm chart for service %v output: \n%v", sd.ServiceName, output) + return "", err } } return "", nil } - -func (c Configurd) ServiceDeployments(baseDir, namespace, deployment string) ([]ServiceDeployment, error) { - file, err := os.Open(path.Join(baseDir, defaultNamespaceDir, namespace, deployment+defaultConfigFileExt)) - defer file.Close() - if err != nil { - return []ServiceDeployment{}, err - } - - var wrapper struct { - ServiceDeployments []ServiceDeployment `yaml:"services"` - } - if err := yaml.NewDecoder(file).Decode(&wrapper); err != nil { - return []ServiceDeployment{}, fmt.Errorf("could not decode service: %w", err) - } - - for i, sd := range wrapper.ServiceDeployments { - svc, err := c.Service(sd.ServiceName) - if err != nil { - log.Fatal(err) - } - wrapper.ServiceDeployments[i].chart = svc.Chart - wrapper.ServiceDeployments[i].namespace = namespace - } - return wrapper.ServiceDeployments, nil -}