func RuntimeUnset(configStore *config.Store, app, env, pool string, options RuntimeOptions) (bool, error) { cfg, err := configStore.GetApp(app, env) if err != nil { return false, err } if options.Ps != 0 { cfg.SetProcesses(pool, -1) } if options.Memory != "" { cfg.SetMemory(pool, "") } vhosts := strings.Split(cfg.Env()["VIRTUAL_HOST"], ",") if options.VirtualHost != "" && utils.StringInSlice(options.VirtualHost, vhosts) { vhosts = utils.RemoveStringInSlice(options.VirtualHost, vhosts) cfg.EnvSet("VIRTUAL_HOST", strings.Join(vhosts, ",")) } if options.Port != "" { cfg.EnvSet("GALAXY_PORT", "") } return configStore.UpdateApp(cfg, env) }
func RuntimeSet(configStore *config.Store, app, env, pool string, options RuntimeOptions) (bool, error) { cfg, err := configStore.GetApp(app, env) if err != nil { return false, err } if options.Ps != 0 && options.Ps != cfg.GetProcesses(pool) { cfg.SetProcesses(pool, options.Ps) } if options.Memory != "" && options.Memory != cfg.GetMemory(pool) { cfg.SetMemory(pool, options.Memory) } vhosts := []string{} vhostsFromEnv := cfg.Env()["VIRTUAL_HOST"] if vhostsFromEnv != "" { vhosts = strings.Split(cfg.Env()["VIRTUAL_HOST"], ",") } if options.VirtualHost != "" && !utils.StringInSlice(options.VirtualHost, vhosts) { vhosts = append(vhosts, options.VirtualHost) cfg.EnvSet("VIRTUAL_HOST", strings.Join(vhosts, ",")) } if options.Port != "" { cfg.EnvSet("GALAXY_PORT", options.Port) } return configStore.UpdateApp(cfg, env) }
func ConfigList(configStore *config.Store, app, env string) error { cfg, err := configStore.GetApp(app, env) if err != nil { return err } if cfg == nil { return fmt.Errorf("unable to list config for %s.", app) } keys := sort.StringSlice{"ENV"} for k, _ := range cfg.Env() { keys = append(keys, k) } keys.Sort() for _, k := range keys { if k == "ENV" { log.Printf("%s=%s\n", k, env) continue } fmt.Printf("%s=%s\n", k, cfg.Env()[k]) } return nil }
func AppDeploy(configStore *config.Store, serviceRuntime *runtime.ServiceRuntime, app, env, version string) error { log.Printf("Pulling image %s...", version) image, err := serviceRuntime.PullImage(version, "") if image == nil || err != nil { return fmt.Errorf("unable to pull %s. Has it been released yet?", version) } svcCfg, err := configStore.GetApp(app, env) if err != nil { return fmt.Errorf("unable to deploy app: %s.", err) } if svcCfg == nil { return fmt.Errorf("app %s does not exist. Create it first.", app) } svcCfg.SetVersion(version) svcCfg.SetVersionID(utils.StripSHA(image.ID)) updated, err := configStore.UpdateApp(svcCfg, env) if err != nil { return fmt.Errorf("could not store version: %s", err) } if !updated { return fmt.Errorf("%s NOT deployed.", version) } log.Printf("Deployed %s.\n", version) return nil }
func AppShell(configStore *config.Store, serviceRuntime *runtime.ServiceRuntime, app, env, pool string) error { appCfg, err := configStore.GetApp(app, env) if err != nil { return fmt.Errorf("unable to run command: %s.", err) } err = serviceRuntime.StartInteractive(env, pool, appCfg) if err != nil { return fmt.Errorf("could not start container: %s", err) } return nil }
func ConfigGet(configStore *config.Store, app, env string, envVars []string) error { cfg, err := configStore.GetApp(app, env) if err != nil { return err } for _, arg := range envVars { fmt.Printf("%s=%s\n", strings.ToUpper(arg), cfg.Env()[strings.ToUpper(arg)]) } return nil }
func AppRun(configStore *config.Store, serviceRuntime *runtime.ServiceRuntime, app, env string, args []string) error { appCfg, err := configStore.GetApp(app, env) if err != nil { return fmt.Errorf("unable to run command: %s.", err) } _, err = serviceRuntime.RunCommand(env, appCfg, args) if err != nil { return fmt.Errorf("could not start container: %s", err) } return nil }
// Balanced returns the number of instances that should be run on the host // according to the desired state for the app in the given env and pool. The // number returned for the host represent an approximately equal distribution // across all hosts. func Balanced(configStore *config.Store, hostId, app, env, pool string) (int, error) { hosts, err := configStore.ListHosts(env, pool) if err != nil { return 0, err } cfg, err := configStore.GetApp(app, env) if err != nil { return 0, err } desired := cfg.GetProcesses(pool) if desired == 0 { return 0, nil } if desired == -1 { return 1, nil } hostIds := []string{} for _, h := range hosts { hostIds = append(hostIds, h.HostIP) } sort.Strings(hostIds) hostIdx := -1 for i, v := range hostIds { if v == hostId { hostIdx = i break } } if hostIdx < 0 { return 0, nil } count := 0 for i := 0; i < desired; i++ { if i%len(hosts) == hostIdx { count = count + 1 } } return count, nil }
func ConfigUnset(configStore *config.Store, app, env string, envVars []string) error { if len(envVars) == 0 { return fmt.Errorf("no config values specified.") } svcCfg, err := configStore.GetApp(app, env) if err != nil { return fmt.Errorf("unable to unset config: %s.", err) } updated := false for _, arg := range envVars { k := strings.ToUpper(strings.TrimSpace(arg)) if k == "ENV" || svcCfg.EnvGet(k) == "" { log.Warnf("%s cannot be unset.", k) continue } log.Printf("%s\n", k) svcCfg.EnvSet(strings.ToUpper(arg), "") updated = true } if !updated { return fmt.Errorf("Configuration NOT changed for %s", app) } updated, err = configStore.UpdateApp(svcCfg, env) if err != nil { return fmt.Errorf("ERROR: Unable to unset config: %s.", err) } if !updated { return fmt.Errorf("Configuration NOT changed for %s", app) } log.Printf("Configuration changed for %s. v%d.\n", app, svcCfg.ID()) return nil }
func ConfigSet(configStore *config.Store, app, env string, envVars []string) error { if len(envVars) == 0 { bytes, err := ioutil.ReadAll(os.Stdin) if err != nil { return err } envVars = strings.Split(string(bytes), "\n") } if len(envVars) == 0 { return fmt.Errorf("no config values specified.") } svcCfg, err := configStore.GetApp(app, env) if err != nil { return fmt.Errorf("unable to set config: %s.", err) } if svcCfg == nil { svcCfg = configStore.NewAppConfig(app, "") } updated := false for _, arg := range envVars { if strings.TrimSpace(arg) == "" { continue } if !strings.Contains(arg, "=") { return fmt.Errorf("bad config variable format: %s", arg) } sep := strings.Index(arg, "=") k := strings.ToUpper(strings.TrimSpace(arg[0:sep])) v := strings.TrimSpace(arg[sep+1:]) if k == "ENV" { log.Warnf("%s cannot be updated.", k) continue } log.Printf("%s=%s\n", k, v) svcCfg.EnvSet(k, v) updated = true } if !updated { return fmt.Errorf("configuration NOT changed for %s", app) } updated, err = configStore.UpdateApp(svcCfg, env) if err != nil { return fmt.Errorf("unable to set config: %s.", err) } if !updated { return fmt.Errorf("configuration NOT changed for %s", app) } log.Printf("Configuration changed for %s. v%d\n", app, svcCfg.ID()) return nil }
func pruneShuttleBackends(configStore *config.Store, env, shuttleAddr string) { if client == nil { return } config, err := client.GetConfig() if err != nil { log.Errorf("ERROR: Unable to get shuttle config: %s", err) return } registrations, err := configStore.ListRegistrations(env) if err != nil { log.Errorf("ERROR: Unable to list registrations: %s", err) return } // FIXME: THERE SHOULD HAVE BEEN AN ERROR IF `len(registrations) == 0` IS WRONG! if len(registrations) == 0 { // If there are no registrations, skip pruning it because we might be in a bad state and // don't want to inadvertently unregister everything. Shuttle will handle the down // nodes if they are really down. return } for _, service := range config.Services { app, err := configStore.GetApp(service.Name, env) if err != nil { log.Errorf("ERROR: Unable to load app %s: %s", app, err) continue } pools, err := configStore.ListAssignedPools(env, service.Name) if err != nil { log.Errorf("ERROR: Unable to list pool assignments for %s: %s", service.Name, err) continue } if app == nil || len(pools) == 0 { err := client.RemoveService(service.Name) if err != nil { log.Errorf("ERROR: Unable to remove service %s from shuttle: %s", service.Name, err) } log.Printf("Unregisterred shuttle service %s", service.Name) continue } for _, backend := range service.Backends { backendExists := false for _, r := range registrations { if backend.Name == r.ContainerID[0:12] { backendExists = true break } } if !backendExists { err := client.RemoveBackend(service.Name, backend.Name) if err != nil { log.Errorf("ERROR: Unable to remove backend %s from shuttle: %s", backend.Name, err) } log.Printf("Unregisterred shuttle backend %s", backend.Name) } } } }
func registerShuttle(configStore *config.Store, env, pool, shuttleAddr string) { if client == nil { return } registrations, err := configStore.ListRegistrations(env) if err != nil { log.Errorf("ERROR: Unable to list registrations: %s", err) return } backends := make(map[string]*shuttle.ServiceConfig) for _, r := range registrations { // No service ports exposed on the host, skip it. if r.ExternalAddr() == "" { continue } service := backends[r.Name] if service == nil { service = &shuttle.ServiceConfig{ Name: r.Name, VirtualHosts: r.VirtualHosts, } if r.Port != "" { service.Addr = "0.0.0.0:" + r.Port } backends[r.Name] = service } b := shuttle.BackendConfig{ Name: r.ContainerID[0:12], Addr: r.ExternalAddr(), CheckAddr: r.ExternalAddr(), } service.Backends = append(service.Backends, b) // lookup the VIRTUAL_HOST_%d environment variables and load them into the ServiceConfig errorPages := make(map[string][]int) for vhostCode, url := range r.ErrorPages { code := 0 n, err := fmt.Sscanf(vhostCode, "VIRTUAL_HOST_%d", &code) if err != nil || n == 0 { continue } errorPages[url] = append(errorPages[url], code) } if len(errorPages) > 0 { service.ErrorPages = errorPages } app, err := configStore.GetApp(service.Name, env) if err != nil { log.Errorf("ERROR: Unable to get app for service %s: %s", service.Name, err) continue } service.MaintenanceMode = app.GetMaintenanceMode(pool) } for _, service := range backends { err := client.UpdateService(service) if err != nil { log.Errorf("ERROR: Unable to register shuttle service: %s", err) } } }