// Try to Tooligure a project by parsing yaml from a byte stream func (tools *Tools) from_ToolYamlBytes(logger log.Log, project *conf.Project, yamlBytes []byte) bool { if project != nil { // token replace tokens := &project.Tokens yamlBytes = []byte(tokens.TokenReplace(string(yamlBytes))) } var yaml_tools map[string]map[string]interface{} err := yaml.Unmarshal(yamlBytes, &yaml_tools) if err != nil { logger.Warning("Could not parse tool yaml:" + err.Error()) return false } for name, tool_struct := range yaml_tools { switch tool_struct["Type"] { case "script": json_tool, _ := json.Marshal(tool_struct) var scriptTool Tool_Script err := json.Unmarshal(json_tool, &scriptTool) if err != nil { logger.Warning("Couldn't process tool [" + name + "] :" + err.Error()) continue } tool := Tool(&scriptTool) tool.Init(logger.MakeChild("SCRIPT:"+name), project) tools.SetTool(name, tool) } } return true }
func (operation *BuildOperation) Run(logger log.Log) bool { logger.Info("Running operation: build") logger.Debug(log.VERBOSITY_DEBUG, "Run:Targets", operation.targets.TargetOrder()) for _, targetID := range operation.targets.TargetOrder() { target, targetExists := operation.targets.Target(targetID) if !targetExists { // this is strange logger.Warning("Internal target error, was told to use a target that doesn't exist") continue } node, hasNode := target.Node() nodeLogger := logger.MakeChild(targetID) if !hasNode { nodeLogger.Info("No node [" + node.MachineName() + "]") } else if !node.Can("build") { nodeLogger.Info("Node doesn't build [" + node.MachineName() + "]") } else { nodeLogger.Message("Building node") node.Client().Build(nodeLogger, operation.force) } } return true }
func (operation *InfoOperation) Run(logger log.Log) bool { logger.Message("RUNNING INFO OPERATION") logger.Debug(log.VERBOSITY_DEBUG, "Run:Targets", operation.targets.TargetOrder()) for _, targetID := range operation.targets.TargetOrder() { target, targetExists := operation.targets.Target(targetID) node, hasNode := target.Node() _, hasInstances := target.Instances() if !targetExists { // this is strange logger.Warning("Internal target error, was told to use a target that doesn't exist") continue } nodeLogger := logger.MakeChild(targetID) if hasNode { nodeLogger.Message(targetID + " Information") node.Client().NodeInfo(nodeLogger) } else { nodeLogger.Message("No node [" + node.MachineName() + "]") } if hasInstances { node.Instances().Client().InstancesInfo(nodeLogger) } else { nodeLogger.Message("|-- No instances [" + node.MachineName() + "]") } } return true }
func (client *FSouza_NodeClient) Destroy(logger log.Log, force bool) bool { // Get the image name image, tag := client.GetImageName() if tag != "" { image += ":" + tag } if !client.HasImage() { logger.Warning("Node has no image to destroy [" + image + "]") return false } options := docker.RemoveImageOptions{ Force: force, } // ask the docker client to remove the image err := client.backend.RemoveImageExtended(image, options) if err != nil { logger.Error("Node image removal failed [" + image + "] => " + err.Error()) return false } else { client.backend.Refresh(true, false) logger.Message("Node image was removed [" + image + "]") return true } }
// Is this project configured enough to run coach func (project *Project) IsValid(logger log.Log) bool { /** * 1. do we have a project coach folder, and does it exist. */ if projectCoachPath, ok := project.Path("project-coach"); ok { if _, err := os.Stat(projectCoachPath); err != nil { logger.Warning(`Could not find a project root .coach folder: - At the root of any coach prpject, must be a .coach folder; - This folder can container project configurations; - The folder is required, because it tells coach where the project base is.`) return false } } else { return false } /** * 2. Do we have a project name * * This is important as it gets used to make image and container names */ if project.Name == "" { logger.Warning(`Coach project has no Name. - A project name can be set in the .coach/conf.yml file. - The Name is used as a base for image and container names.`) return false } return true }
func (operation *StatusOperation) Run(logger log.Log) bool { logger.Message("RUNNING Status OPERATION") logger.Debug(log.VERBOSITY_DEBUG, "Run:Targets", operation.targets.TargetOrder()) for _, targetID := range operation.targets.TargetOrder() { target, targetExists := operation.targets.Target(targetID) node, hasNode := target.Node() instances, hasInstances := target.Instances() if !targetExists { // this is strange logger.Warning("Internal target error, was told to use a target that doesn't exist") continue } nodeLogger := logger.MakeChild(targetID) status := []string{} if hasNode { status = append(status, operation.NodeStatus(nodeLogger, node)...) } else { status = append(status, "No node for target") } if hasInstances { status = append(status, operation.InstancesStatus(nodeLogger, instances)...) } else { status = append(status, "No instances for target") } nodeLogger.Message("[" + strings.Join(status, "][") + "]") } return true }
func (operation *CreateOperation) Run(logger log.Log) bool { logger.Info("Running operation: create") logger.Debug(log.VERBOSITY_DEBUG, "Run:Targets", operation.targets.TargetOrder()) for _, targetID := range operation.targets.TargetOrder() { target, targetExists := operation.targets.Target(targetID) if !targetExists { // this is strange logger.Warning("Internal target error, was told to use a target that doesn't exist") continue } node, hasNode := target.Node() instances, hasInstances := target.Instances() nodeLogger := logger.MakeChild(targetID) if !hasNode { nodeLogger.Warning("No node [" + node.MachineName() + "]") } else if !node.Can("create") { nodeLogger.Info("Node doesn't create [" + node.MachineName() + ":" + node.Type() + "]") } else if !hasInstances { nodeLogger.Info("No valid instances specified in target list [" + node.MachineName() + "]") } else { nodeLogger.Message("Creating instance containers") for _, id := range instances.InstancesOrder() { instance, _ := instances.Instance(id) instance.Client().Create(logger, []string{}, operation.force) } } } return true }
func (client *FSouza_InstanceClient) Commit(logger log.Log, tag string, message string) bool { id := client.instance.MachineName() config := client.settings.Config repo := client.settings.Repository author := client.settings.Author if repo == "" { repo, _ = client.GetImageName() } options := docker.CommitContainerOptions{ Container: id, Repository: repo, Tag: tag, Run: &config, } if message != "" { options.Message = message } if author != "" { author = client.conf.Author } _, err := client.backend.CommitContainer(options) if err != nil { logger.Warning("Failed to commit container changes to an image [" + client.instance.Id() + ":" + id + "] : " + tag) return false } else { client.backend.Refresh(true, false) logger.Message("Committed container changes to an image [" + client.instance.Id() + ":" + id + "] : " + tag) return true } }
func (task *InitTaskFileBase) CopyFileRecursive(logger log.Log, path string, source string) bool { sourceAbsPath, ok := task.absolutePath(source, false) if !ok { logger.Warning("Couldn't find copy source " + source) return false } return task.copyFileRecursive(logger, path, sourceAbsPath, "") }
// Try to configure a project by parsing yaml from a byte stream func (project *Project) from_ConfYamlBytes(logger log.Log, yamlBytes []byte) bool { // parse the config file contents as a ConfSource_projectyaml object source := new(conf_Yaml) if err := yaml.Unmarshal(yamlBytes, source); err != nil { logger.Warning("YAML parsing error : " + err.Error()) return false } logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "YAML source:", *source) return source.configureProject(logger, project) }
func (operation *ScaleOperation) Run(logger log.Log) bool { logger.Info("Running operation: scale") logger.Debug(log.VERBOSITY_DEBUG, "Run:Targets", operation.targets.TargetOrder()) if operation.scale == 0 { operation.log.Warning("scale operation was told to scale to 0") return false } for _, targetID := range operation.targets.TargetOrder() { target, targetExists := operation.targets.Target(targetID) if !targetExists { // this is strange logger.Warning("Internal target error, was told to use a target that doesn't exist") continue } node, hasNode := target.Node() nodeLogger := logger.MakeChild(targetID) if !hasNode { nodeLogger.Info("No node [" + node.MachineName() + "]") } else if !node.Can("scale") { nodeLogger.Info("Node doesn't Scale [" + node.MachineName() + "]") } else { nodeLogger.Message("Scaling node " + node.Id()) if operation.scale > 0 { count := operation.ScaleUpNumber(nodeLogger, node.Instances(), operation.scale) if count == 0 { nodeLogger.Warning("Scale operation could not scale up any new instances of node") } else if count < operation.scale { nodeLogger.Warning("Scale operation could not scale up all of the requested instances of node. " + strconv.FormatInt(int64(count+1), 10) + " started.") } else { nodeLogger.Message("Scale operation scaled up " + strconv.FormatInt(int64(count), 10) + " instances") } } else { count := operation.ScaleDownNumber(nodeLogger, node.Instances(), -operation.scale) if count == 0 { nodeLogger.Warning("Scale operation could not scale down any new instances of node") } else if count < (-operation.scale) { nodeLogger.Warning("Scale operation could not scale down all of the requested instances of node. " + strconv.FormatInt(int64(count+1), 10) + " stopped.") } else { nodeLogger.Message("Scale operation scaled down " + strconv.FormatInt(int64(count), 10) + " instances") } } } } return true }
func (task *InitTaskFileCopy) RunTask(logger log.Log) bool { if task.path == "" || task.root == "" || task.source == "" { return false } if task.CopyFileRecursive(logger, task.path, task.source) { logger.Message("--> Copied file : " + task.source + " -> " + task.path) return true } else { logger.Warning("--> Failed to copy file : " + task.source + " -> " + task.path) return false } }
func (task *InitTaskRemoteFile) RunTask(logger log.Log) bool { if task.path == "" || task.root == "" || task.url == "" { return false } if task.CopyRemoteFile(logger, task.path, task.url) { logger.Message("--> Copied remote file : " + task.url + " -> " + task.path) return true } else { logger.Warning("--> Failed to copy remote file : " + task.url) return false } }
func (task *InitTaskFile) RunTask(logger log.Log) bool { if task.path == "" { return false } if task.MakeFile(logger, task.path, task.contents) { logger.Message("--> Created file : " + task.path) return true } else { logger.Warning("--> Failed to create file : " + task.path) return false } }
// Try to configure a project by parsing yaml from a conf file func (nodes *Nodes) from_NodesYamlFilePath(logger log.Log, project *conf.Project, clientFactories *ClientFactories, yamlFilePath string, overwrite bool) bool { // read the config file yamlFile, err := ioutil.ReadFile(yamlFilePath) if err != nil { logger.Debug(log.VERBOSITY_DEBUG_LOTS, "Could not read a YAML file: "+err.Error()) return false } if !nodes.from_NodesYamlBytes(logger.MakeChild(yamlFilePath), project, clientFactories, yamlFile, overwrite) { logger.Warning("YAML marshalling of the YAML nodes file failed [" + yamlFilePath + "]: " + err.Error()) return false } return true }
// Try to configure factories by parsing yaml from a byte stream func (clientFactories *ClientFactories) from_ClientFactoriesYamlBytes(logger log.Log, project *conf.Project, yamlBytes []byte) bool { if project != nil { // token replace tokens := &project.Tokens yamlBytes = []byte(tokens.TokenReplace(string(yamlBytes))) } var yaml_clients map[string]map[string]interface{} err := yaml.Unmarshal(yamlBytes, &yaml_clients) if err != nil { logger.Warning("YAML parsing error : " + err.Error()) return false } logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "YAML source:", yaml_clients) for name, client_struct := range yaml_clients { clientType := "" client_json, _ := json.Marshal(client_struct) logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "Single client JSON:", string(client_json)) if clientType_struct, ok := client_struct["Type"]; ok { clientType, _ = clientType_struct.(string) } else { clientType = name } switch strings.ToLower(clientType) { case "docker": fallthrough case "fsouza": clientFactorySettings := &FSouza_ClientFactorySettings{} err := json.Unmarshal(client_json, clientFactorySettings) if err != nil { logger.Warning("Factory definition failed to configure client factory :" + err.Error()) logger.Debug(log.VERBOSITY_DEBUG, "Factory configuration json: ", string(client_json), clientFactorySettings) continue } factory := FSouza_ClientFactory{} if !factory.Init(logger.MakeChild(clientType), project, ClientFactorySettings(clientFactorySettings)) { logger.Error("Failed to initialize FSouza factory from client factory configuration: " + err.Error()) continue } // Add this factory to the factory list logger.Debug(log.VERBOSITY_DEBUG_LOTS, "Client Factory Created [Client_DockerFSouzaFactory]", factory) clientFactories.AddClientFactory(clientType, ClientFactory(&factory)) case "": logger.Warning("Client registration failure, client has a bad value for 'Type'") default: logger.Warning("Client registration failure, client has an unknown value for 'Type' :" + clientType) } } return true }
// Try to configure a project by parsing yaml from a conf file func (project *Project) from_ConfYamlFilePath(logger log.Log, yamlFilePath string) bool { // read the config file yamlFile, err := ioutil.ReadFile(yamlFilePath) if err != nil { logger.Debug(log.VERBOSITY_DEBUG_LOTS, "Could not read a YAML file: "+err.Error()) return false } if !project.from_ConfYamlBytes(logger.MakeChild(yamlFilePath), yamlFile) { logger.Warning("YAML marshalling of the YAML conf file failed [" + yamlFilePath + "]: " + err.Error()) return false } return true }
func (node *PullNode) Init(logger log.Log, name string, project *conf.Project, client Client, instancesSettings InstancesSettings) bool { node.BaseNode.Init(logger, name, project, client, instancesSettings) settingsInterface := instancesSettings.Settings() switch settingsInterface.(type) { case FixedInstancesSettings: logger.Warning("Pull node cannot be configured to use fixed instances. Using null instance instead.") node.defaultInstances(logger, client, instancesSettings) case ScaledInstancesSettings: logger.Warning("Pull node cannot be configured to use scaled instances. Using null instance instead.") node.defaultInstances(logger, client, instancesSettings) case SingleInstancesSettings: logger.Warning("Pull node cannot be configured to use single instances. Using null instance instead.") node.defaultInstances(logger, client, instancesSettings) case TemporaryInstancesSettings: logger.Warning("Pull node cannot be configured to use disposable instances. Using null instance instead.") node.defaultInstances(logger, client, instancesSettings) default: node.defaultInstances(logger, client, instancesSettings) } node.instances.Init(logger, node.MachineName(), client, instancesSettings) logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "Built new node:", node.client) return true }
func (operation *PauseOperation) Run(logger log.Log) bool { logger.Info("Running operation: pause") logger.Debug(log.VERBOSITY_DEBUG, "Run:Targets", operation.targets.TargetOrder()) for _, targetID := range operation.targets.TargetOrder() { target, targetExists := operation.targets.Target(targetID) if !targetExists { // this is strange logger.Warning("Internal target error, was told to use a target that doesn't exist") continue } node, hasNode := target.Node() instances, hasInstances := target.Instances() nodeLogger := logger.MakeChild(targetID) if !hasNode { nodeLogger.Warning("No node [" + node.MachineName() + "]") } else if !node.Can("pause") { nodeLogger.Info("Node doesn't Pause [" + node.MachineName() + ":" + node.Type() + "]") } else if !hasInstances { nodeLogger.Info("No valid instances specified in target list [" + node.MachineName() + "]") } else { nodeLogger.Message("Pausing instances") if !instances.IsFiltered() { nodeLogger.Info("Switching to using all instances") instances.UseAll() } for _, id := range instances.InstancesOrder() { instance, _ := instances.Instance(id) if !instance.IsRunning() { if !instance.IsReady() { nodeLogger.Info("Instance will not be paused as it is not ready :" + id) } else { nodeLogger.Info("Instance will not be paused as it is not running :" + id) } } else { instance.Client().Pause(logger) } } } } return true }
// Try to configure help by parsing yaml from a byte stream func (help *Help) from_HelpYamlBytes(logger log.Log, project *conf.Project, yamlBytes []byte) bool { if project != nil { // token replace tokens := &project.Tokens yamlBytes = []byte(tokens.TokenReplace(string(yamlBytes))) logger.Debug(log.VERBOSITY_DEBUG_LOTS, "Tokenized Bytes", string(yamlBytes)) } if err := yaml.Unmarshal(yamlBytes, help); err != nil { logger.Warning("YAML parsing error : " + err.Error()) // logger.Debug(log.VERBOSITY_DEBUG, "YAML parsing error : " + err.Error(), string(yamlBytes)) return false } return true }
func (client *FSouza_NodeClient) Build(logger log.Log, force bool) bool { image, tag := client.GetImageName() if client.settings.BuildPath == "" { logger.Warning("Node image [" + image + ":" + tag + "] not built as an empty path was provided. You must point Build: to a path inside .coach") return false } if !force && client.HasImage() { logger.Info("Node image [" + image + ":" + tag + "] not built as an image already exists. You can force this operation to build this image") return false } // determine an absolute buildPath to the build, for Docker to use. buildPath := "" for _, confBuildPath := range client.conf.Paths.GetConfSubPaths(client.settings.BuildPath) { logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "Looking for Build: "+confBuildPath) if _, err := os.Stat(confBuildPath); !os.IsNotExist(err) { buildPath = confBuildPath break } } if buildPath == "" { logger.Error("No matching build path could be found [" + client.settings.BuildPath + "]") } options := docker.BuildImageOptions{ Name: image + ":" + tag, ContextDir: buildPath, RmTmpContainer: true, OutputStream: logger, } logger.Info("Building node image [" + image + ":" + tag + "] From build path [" + buildPath + "]") // ask the docker client to build the image err := client.backend.BuildImage(options) if err != nil { logger.Error("Node build failed [" + client.node.MachineName() + "] in build path [" + buildPath + "] => " + err.Error()) return false } else { client.backend.Refresh(true, false) logger.Message("Node succesfully built image [" + image + ":" + tag + "] From path [" + buildPath + "]") return true } }
func (task *InitTaskFileStringReplace) RunTask(logger log.Log) bool { if task.path == "" || task.root == "" || task.oldString == "" || task.newString == "" { return false } if task.replaceCount == 0 { task.replaceCount = -1 } if task.FileStringReplace(logger, task.path, task.oldString, task.newString, task.replaceCount) { logger.Message("--> performed string replace on file : " + task.path) return true } else { logger.Warning("--> Failed to perform string replace on file : " + task.path) return false } }
func (node *node_yaml_v2) GetClient(logger log.Log, clientFactories *ClientFactories) (Client, bool) { // if a docker client was configured then try to take it. // if !(node.Docker.Config.Image=="" && node.Docker.BuildPath=="") { if factory, ok := clientFactories.MatchClientFactory(FactoryMatchRequirements{Type: "docker"}); ok { if client, ok := factory.MakeClient(logger, ClientSettings(&node.Docker)); ok { return client, true } } else { logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "Failed to match client factory:", factory) } // } logger.Warning("Invalid YAML node settings: improper client configuration") return nil, false }
func (settings *FSouza_ClientSettings) Prepare(logger log.Log, nodes *Nodes) bool { settings.log = logger /** * Remap all binds so that they are based on the project folder * - any relative path is remapped to be from the project root * - any path starting with ~ is remapped to the user home flder * - any absolute paths are left as is */ if settings.Host.Binds != nil { var binds []string for index, bind := range settings.Host.Binds { binds = strings.SplitN(bind, ":", 3) bindRoot := binds[0] // this is the bind source if path.IsAbs(bindRoot) { continue } else if bindRoot[0:1] == "~" { // one would think that path can handle such terminology if rootPath, ok := settings.conf.Paths.Path("user-home"); ok { bindRoot = path.Join(rootPath, bindRoot[1:]) } } else { if rootPath, ok := settings.conf.Paths.Path("project-root"); ok { bindRoot = path.Join(rootPath, bindRoot[:]) } } // report a warning if the bind path does not exists. // This sometimes causes issues as Docker will try to create the // host bind path on the fly, as the root user if _, err := os.Stat(bindRoot); os.IsNotExist(err) { logger.Warning("Node settings included a bind path that does not exist. Docker will try to create the local path as a file:" + binds[0] + " .Note that in some cases, related containers may report a missing image error") } if bindRoot != binds[0] { binds[0] = bindRoot settings.Host.Binds[index] = strings.Join(binds, ":") } } } // build dependencies by looking at the Host Links and VolumesFrom lists settings.dependenciesFromConfig(logger, nodes, settings.Host.Links) settings.dependenciesFromConfig(logger, nodes, settings.Host.VolumesFrom) return true }
// MakeCoachProject Project constructor for building a project based on a project path func MakeCoachProject(logger log.Log, workingDir string, environment string) (project *Project) { project = &Project{ Environment: environment, // base on the default environment Paths: MakePaths(), // empty typesafe paths object Tokens: MakeTokens(), // empty tokens object Flags: MakeProjectFlags(), // empty flags object } /** * 1. try to get some base default configuration, seeing if there is a * project .coach folder above the workingdir (or in it) or maybe * there's a user's ~/.coach */ project.from_DefaultPaths(logger.MakeChild("defaults"), workingDir) // set the two project paths, to be the most important project.setConfPath("project-coach") // set the user conf paths, to be the least important project.setConfPath("user-coach") /** * 2. Look for YAML configurations in the Configuration Paths */ project.from_ConfYaml(logger.MakeChild("confyaml")) /** * 3. Try to load secrets from configuration paths */ project.from_EnvironmentsPath(logger.MakeChild("environment")) /** * 4. Try to load secrets from configuration paths */ project.from_SecretsYaml(logger.MakeChild("secrets")) /** * 5. Run the project prepare, which will validate the configuration */ if !project.Prepare(logger) { logger.Warning("Coach configuration processing failed") } return project }
func (task *InitTaskFileBase) copyFileRecursive(logger log.Log, destinationRootPath string, sourceRootPath string, sourcePath string) bool { fullPath := sourceRootPath if sourcePath != "" { fullPath = path.Join(fullPath, sourcePath) } // get properties of source dir info, err := os.Stat(fullPath) if err != nil { // @TODO do something log : source doesn't exist logger.Warning("File does not exist :" + fullPath) return false } mode := info.Mode() if mode.IsDir() { directory, _ := os.Open(fullPath) objects, err := directory.Readdir(-1) if err != nil { // @TODO do something log : source doesn't exist logger.Warning("Could not open directory") return false } for _, obj := range objects { //childSourcePath := source + "/" + obj.Name() childSourcePath := path.Join(sourcePath, obj.Name()) if !task.copyFileRecursive(logger, destinationRootPath, sourceRootPath, childSourcePath) { logger.Warning("Resursive copy failed") } } } else { // add file copy destinationPath := path.Join(destinationRootPath, sourcePath) if task.CopyFile(logger, destinationPath, sourceRootPath) { logger.Info("--> Copied file (recursively): " + sourcePath + " [from " + sourceRootPath + "]") return true } else { logger.Warning("--> Failed to copy file: " + sourcePath + " [from " + sourceRootPath + "]") return false } return true } return true }
func (task *InitTaskFileBase) MakeDir(logger log.Log, makePath string, pathIsFile bool) bool { if makePath == "" { return true // it's already made } if pathDirectory, ok := task.absolutePath(makePath, true); !ok { logger.Warning("Invalid directory path: " + pathDirectory) return false } pathDirectory := path.Join(task.root, makePath) if pathIsFile { pathDirectory = path.Dir(pathDirectory) } if err := os.MkdirAll(pathDirectory, 0777); err != nil { // @todo something log return false } return true }
func (task *InitTaskFileBase) CopyRemoteFile(logger log.Log, destinationPath string, sourcePath string) bool { if destinationPath == "" || sourcePath == "" { return false } response, err := http.Get(sourcePath) if err != nil { logger.Warning("Could not open remote URL: " + sourcePath) return false } defer response.Body.Close() sourceContent, err := ioutil.ReadAll(response.Body) if err != nil { logger.Warning("Could not read remote file: " + sourcePath) return false } return task.MakeFile(logger, destinationPath, string(sourceContent)) }
// perform a string replace on file contents func (task *InitTaskFileBase) FileStringReplace(logger log.Log, targetPath string, oldString string, newString string, replaceCount int) bool { targetPath, ok := task.absolutePath(targetPath, false) if !ok { logger.Warning("Invalid string replace path: " + targetPath) return false } contents, err := ioutil.ReadFile(targetPath) if err != nil { logger.Error(err.Error()) } contents = []byte(strings.Replace(string(contents), oldString, newString, replaceCount)) err = ioutil.WriteFile(targetPath, contents, 0644) if err != nil { logger.Error(err.Error()) } return true }
func (instances *ScaledInstances) Init(logger log.Log, machineName string, client Client, settings InstancesSettings) bool { instances.BaseInstances.Init(logger, machineName, client, settings) switch asserted := settings.Settings().(type) { case ScaledInstancesSettings: // sanity check if asserted.Initial < 0 { asserted.Maximum = INSTANCES_SCALED_DEFAULT_INITIAL logger.Warning("Scaled instances Initial count was invalid. Switching to the default value") } if asserted.Maximum < 1 { asserted.Maximum = INSTANCES_SCALED_DEFAULT_MAXIMUM logger.Warning("Scaled instances Maximum was invalid. Switching to the default value") } if asserted.Initial > asserted.Maximum { asserted.Maximum = asserted.Initial logger.Warning("Scaled instances Maximum is lower than the Initial value. Using Initial as Maximum.") } instances.settings = asserted default: instances.settings = ScaledInstancesSettings{Initial: INSTANCES_SCALED_DEFAULT_INITIAL, Maximum: INSTANCES_SCALED_DEFAULT_MAXIMUM} } return true }