From 919d7342e723fe109d92e5d84f4b3b73beefdc8c Mon Sep 17 00:00:00 2001 From: Denis Shatilov Date: Fri, 23 Feb 2018 23:04:22 -0800 Subject: [PATCH] Multiple Sidekick functionality added. --- main.go | 41 ++++++++++++++-------------------- plugin.go | 67 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/main.go b/main.go index 400d9c6..7660865 100755 --- a/main.go +++ b/main.go @@ -8,19 +8,6 @@ import ( "github.com/urfave/cli" ) -type Rancher struct { - URL string `json:"url"` - AccessKey string `json:"access_key"` - SecretKey string `json:"secret_key"` - Service string `json:"service"` - Image string `json:"docker_image"` - StartFirst bool `json:"start_first"` - Confirm bool `json:"confirm"` - Timeout int `json:"timeout"` - IntervalMillis int64 `json:"interval_millis"` - BatchSize int64 `json:"batch_size"` -} - var build string // build number set at compile-time func main() { @@ -52,6 +39,11 @@ func main() { Usage: "Service to act on", EnvVar: "PLUGIN_SERVICE", }, + cli.StringSliceFlag{ + Name: "sidekick", + Usage: "Service's sidekick name and image separated by the space, supports multiple flags", + EnvVar: "PLUGIN_SIDEKICK", + }, cli.StringFlag{ Name: "docker-image", Usage: "image to use", @@ -99,17 +91,18 @@ func main() { func run(c *cli.Context) error { plugin := Plugin{ - URL: c.String("url"), - Key: c.String("access-key"), - Secret: c.String("secret-key"), - Service: c.String("service"), - DockerImage: c.String("docker-image"), - StartFirst: c.BoolT("start-first"), - Confirm: c.Bool("confirm"), - Timeout: c.Int("timeout"), - IntervalMillis: c.Int64("interval-millis"), - BatchSize: c.Int64("batch-size"), - YamlVerified: c.BoolT("yaml-verified"), + URL: c.String("url"), + Key: c.String("access-key"), + Secret: c.String("secret-key"), + Service: c.String("service"), + SidekickDockerImage: c.StringSlice("sidekick"), + DockerImage: c.String("docker-image"), + StartFirst: c.BoolT("start-first"), + Confirm: c.Bool("confirm"), + Timeout: c.Int("timeout"), + IntervalMillis: c.Int64("interval-millis"), + BatchSize: c.Int64("batch-size"), + YamlVerified: c.BoolT("yaml-verified"), } return plugin.Exec() } diff --git a/plugin.go b/plugin.go index 6045511..b47e86b 100755 --- a/plugin.go +++ b/plugin.go @@ -11,29 +11,27 @@ import ( ) type Plugin struct { - URL string - Key string - Secret string - Service string - DockerImage string - StartFirst bool - Confirm bool - Timeout int - IntervalMillis int64 - BatchSize int64 - YamlVerified bool + URL string + Key string + Secret string + Service string + SidekickDockerImage []string + DockerImage string + StartFirst bool + Confirm bool + Timeout int + IntervalMillis int64 + BatchSize int64 + YamlVerified bool } func (p *Plugin) Exec() error { log.Info("Drone Rancher Plugin built") - if p.URL == "" || p.Key == "" || p.Secret == "" { + if p.URL == "" || p.Key == "" || p.Secret == "" || p.Service == "" { return errors.New("Eek: Must have url, key, secret, and service definied") } - if !strings.HasPrefix(p.DockerImage, "docker:") { - p.DockerImage = fmt.Sprintf("docker:%s", p.DockerImage) - } var wantedService, wantedStack string if strings.Contains(p.Service, "/") { parts := strings.SplitN(p.Service, "/", 2) @@ -58,6 +56,7 @@ func (p *Plugin) Exec() error { // Query stacks with filter name=wantedStack if wantedStack != "" { stacks, err := rancher.Stack.List(&client.ListOpts{Filters: map[string]interface{}{"name": wantedStack}}) + if err != nil { return fmt.Errorf("Failed to list rancher environments: %s", err) } @@ -66,6 +65,7 @@ func (p *Plugin) Exec() error { } // If found add stackID to serviceFilters serviceFilters["stackId"] = stacks.Data[0].Id + } // Query services with prepared filters @@ -77,9 +77,31 @@ func (p *Plugin) Exec() error { return fmt.Errorf("Unable to find service %s", p.Service) } service := services.Data[0] - // Service is found, proceed with upgrade - service.LaunchConfig.ImageUuid = p.DockerImage + + // We want to exit if there is no docker image updates + if p.DockerImage == "" && len(p.SidekickDockerImage) <= 0 { + return fmt.Errorf("Nothing to upgrade") + } + + // Only change value if it's not null. + if p.DockerImage != "" { + // Add prefix when missing to meet Rancher API requirement + service.LaunchConfig.ImageUuid = prepareDockerPrefix(p.DockerImage) + } + + // Iterate over provided sidekick flags + for _, sidekick := range p.SidekickDockerImage { + // Split flag in two from "--sidekick nginx nginx:latest" + parts := strings.SplitN(sidekick, " ", 2) + wantedSidekick := parts[0] + wantedImage := parts[1] + for i, s := range service.SecondaryLaunchConfigs { + if wantedSidekick == s.Name { + service.SecondaryLaunchConfigs[i].ImageUuid = prepareDockerPrefix(wantedImage) + } + } + } upgrade := &client.ServiceUpgrade{} upgrade.InServiceStrategy = &client.InServiceUpgradeStrategy{ LaunchConfig: service.LaunchConfig, @@ -94,7 +116,6 @@ func (p *Plugin) Exec() error { return fmt.Errorf("Unable to upgrade service %s: %s", p.Service, err) } - log.Infof("Upgraded %s to %s", p.Service, p.DockerImage) if p.Confirm { srv, err := retry(func() (interface{}, error) { s, e := rancher.Service.ById(service.Id) @@ -117,11 +138,21 @@ func (p *Plugin) Exec() error { } log.Infof("Finished upgrade %s", p.Service) } + + log.Infof("Upgraded %s to %s", p.Service, p.DockerImage) + return nil } type retryFunc func() (interface{}, error) +func prepareDockerPrefix(image string) string { + if !strings.HasPrefix(image, "docker:") { + image = fmt.Sprintf("docker:%s", image) + } + return image +} + func retry(f retryFunc, timeout time.Duration, interval time.Duration) (interface{}, error) { finish := time.After(timeout) for {