// 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 }
// Constructor for BaseNode func (node *BaseNode) Init(logger log.Log, name string, project *conf.Project, client Client, instancesSettings InstancesSettings) bool { node.log = logger node.conf = project node.name = name node.client = client node.manualDependencies = []string{} instancesMachineName := node.MachineName() settingsInterface := instancesSettings.Settings() switch settingsInterface.(type) { case FixedInstancesSettings: node.instances = Instances(&FixedInstances{}) instancesMachineName += "_fixed_" case TemporaryInstancesSettings: node.instances = Instances(&TemporaryInstances{}) instancesMachineName += "_temp_" case ScaledInstancesSettings: node.instances = Instances(&ScaledInstances{}) instancesMachineName += "_scaled_" case SingleInstancesSettings: node.instances = Instances(&SingleInstances{}) default: node.instances = Instances(&SingleInstances{}) } node.instances.Init(logger, instancesMachineName, client, instancesSettings) logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "Built new node:", node.client) return true }
// scale a node up a certain number of instances func (operation *ScaleOperation) ScaleUpNumber(logger log.Log, instances libs.Instances, number int) int { count := 0 instancesOrder := instances.InstancesOrder() InstanceScaleReturn: for _, instanceId := range instancesOrder { if instance, ok := instances.Instance(instanceId); ok { client := instance.Client() if client.IsRunning() { continue InstanceScaleReturn } else if !client.HasContainer() { // create a new container for this instance client.Create(logger, []string{}, false) } logger.Info("Node Scaling up. Starting instance :" + instanceId) client.Start(logger, false) count++ if count >= number { return count } } } return count }
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 } }
// scale a node down a certain number of instances func (operation *ScaleOperation) ScaleDownNumber(logger log.Log, instances libs.Instances, number int) int { count := 0 instancesOrder := []string{} for _, instanceId := range instances.InstancesOrder() { instancesOrder = append([]string{instanceId}, instancesOrder...) } InstanceScaleReturn: for _, instanceId := range instancesOrder { if instance, ok := instances.Instance(instanceId); ok { client := instance.Client() if !client.IsRunning() { continue InstanceScaleReturn } logger.Info("Node Scaling down. Stopping instance :" + instanceId) client.Stop(logger, operation.force, operation.timeout) if operation.removeStopped { client.Remove(logger, operation.force) } count++ if count >= number { return count } } } return count }
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 (tasks *InitTasks) Init_Demo_Run(logger log.Log, demo string) bool { if demoPath, ok := COACH_DEMO_URLS[demo]; ok { return tasks.Init_Yaml_Run(logger, demoPath) } else { logger.Error("Unknown demo key : " + demo) return false } }
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, "") }
// Use the secrets yaml object to configure a project func (secrets *secrets_Yaml) configureProject(logger log.Log, project *Project) bool { for key, value := range secrets.Secrets { project.SetToken(key, value) } logger.Debug(log.VERBOSITY_DEBUG_STAAAP, "Configured project from YAML secrets") return true }
func (operation *UnknownOperation) Run(logger log.Log) bool { if operation.id == DEFAULT_OPERATION { logger.Error("No operation specified") } else { logger.Error("Unknown operation: " + operation.id) } return false }
// Run all of the prepared operations func (operations *Operations) Run(logger log.Log) { if len(operations.operationsList) == 0 { logger.Error("No operation created") } else { for _, operation := range operations.operationsList { operation.Run(logger.MakeChild(operation.Id())) } } }
// 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 (instances *SingleInstances) Prepare(logger log.Log, client Client, nodes *Nodes, node Node) bool { instances.log = logger logger.Debug(log.VERBOSITY_DEBUG_WOAH, "Prepare: Single Instances") instances.instance = SingleInstance{} instances.instance.Init(logger, INSTANCE_SINGLE_ID, instances.MachineName(), client, true) instances.log.Debug(log.VERBOSITY_DEBUG_WOAH, "Created single instance", instances.instance) return true }
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 (client *FSouza_InstanceClient) Stop(logger log.Log, force bool, timeout uint) bool { id := client.instance.MachineName() err := client.backend.StopContainer(id, timeout) if err != nil { logger.Error("Failed to stop node container [" + id + "] => " + err.Error()) return false } else { client.backend.Refresh(false, true) logger.Message("Node instance stopped [" + id + "]") return true } }
func (client *FSouza_InstanceClient) Unpause(logger log.Log) bool { id := client.instance.MachineName() err := client.backend.UnpauseContainer(id) if err != nil { logger.Error("Failed to unpause Instance [" + client.instance.Id() + "] Container [" + id + "] =>" + err.Error()) return false } else { client.backend.Refresh(false, true) logger.Message("Unpaused Instance [" + client.instance.Id() + "] Container [" + id + "]") 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 *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 } }
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 (operation *InitGenerateOperation) Run(logger log.Log) bool { logger.Info("running init operation:" + operation.output) var writer io.Writer switch operation.output { case "logger": fallthrough case "": writer = logger default: if strings.HasSuffix(operation.output, ".") { operation.output = operation.output + operation.handler } if fileWriter, err := os.Create(operation.output); err == nil { operation.skip = append(operation.skip, operation.output) writer = io.Writer(fileWriter) defer fileWriter.Close() logger.Message("Opening file for init generation output: " + operation.output) } else { logger.Error("Could not open output file to write init to:" + operation.output) } } initialize.Init_Generate(logger.MakeChild("init-generate"), operation.handler, operation.root, operation.skip, operation.sizeLimit, writer) 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 (tasks *InitTasks) Init_User_Run(logger log.Log, template string) bool { if template == "" { logger.Error("You have not provided a template name $/> coach init user {template}") return false } templatePath, ok := tasks.conf.Path("user-templates") if !ok { logger.Error("COACH has no user template path for the current user") return false } sourcePath := path.Join(templatePath, template) if _, err := os.Stat(sourcePath); err != nil { logger.Error("Invalid template path suggested for new project init : [" + template + "] expected path [" + sourcePath + "] => " + err.Error()) return false } logger.Message("Perfoming init operation from user template [" + template + "] : " + sourcePath) tasks.AddFileCopy(tasks.root, sourcePath) tasks.AddMessage("Copied coach template [" + template + "] to init project") tasks.AddFile(".coach/CREATEDFROM.md", `THIS PROJECT WAS CREATED FROM A User Template :`+template) return true }
func (tasks *InitTasks) Init_Git_Run(logger log.Log, source string) bool { if source == "" { logger.Error("You have not provided a git target $/> coach init git https://github.com/aleksijohansson/docker-drupal-coach") return false } url := source path := tasks.root cmd := exec.Command("git", "clone", "--progress", url, path) cmd.Stdin = os.Stdin cmd.Stdout = logger cmd.Stderr = logger err := cmd.Start() if err != nil { logger.Error("Failed to clone the remote repository [" + url + "] => " + err.Error()) return false } logger.Message("Clone remote repository to local project folder [" + url + "]") err = cmd.Wait() if err != nil { logger.Error("Failed to clone the remote repository [" + url + "] => " + err.Error()) return false } tasks.AddMessage("Cloned remote repository [" + url + "] to local project folder") tasks.AddFile(".coach/CREATEDFROM.md", `THIS PROJECT WAS CREATED FROM GIT`) return true }
func (clientFactory *FSouza_ClientFactory) Init(logger log.Log, project *conf.Project, settings ClientFactorySettings) bool { clientFactory.log = logger clientFactory.conf = project // make sure that the settings that were given, where the proper "FSouza_ClientFactory" type typedSettings := settings.Settings() switch asserted := typedSettings.(type) { case *FSouza_ClientFactorySettings: clientFactory.settings = *asserted default: logger.Error("Invalid settings type passed to Fsouza Factory") logger.Debug(log.VERBOSITY_DEBUG, "Settings passed:", asserted) } // if we haven't made an actual fsouza docker client, then do it now if clientFactory.client == nil { if client, pk := clientFactory.makeFsouzaClientWrapper(logger.MakeChild("fsouza")); pk { clientFactory.client = client return true } else { logger.Error("Failed to create actual FSouza Docker client from client factory configuration") return false } } 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 (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 }
// Post initialization preparation func (node *BaseNode) Prepare(logger log.Log, nodes *Nodes) (success bool) { logger.Debug(log.VERBOSITY_DEBUG_WOAH, "Prepare: Base Node") success = true node.log = logger logger.Debug(log.VERBOSITY_DEBUG_WOAH, "Preparing Client", nil) success = success && node.client.Prepare(logger.MakeChild("client"), nodes, node) logger.Debug(log.VERBOSITY_DEBUG_WOAH, "Preparing Instances", nil) success = success && node.instances.Prepare(logger.MakeChild("instances"), node.client, nodes, node) return success }
func Init_Generate(logger log.Log, handler string, path string, skip []string, sizeLimit int64, output io.Writer) bool { logger.Message("GENERATING INIT") var generator Generator switch handler { case "test": generator = Generator(&TestInitGenerator{logger: logger, output: output}) case "yaml": generator = Generator(&YMLInitGenerator{logger: logger, output: output}) default: logger.Error("Unknown init generator (handler) " + handler) return false } iterator := GenerateIterator{ logger: logger, output: output, skip: skip, sizeLimit: sizeLimit, generator: generator, } if iterator.Generate(path) { logger.Message("FINISHED GENERATING YML INIT") return true } else { logger.Error("ERROR OCCURRED GENERATING YML INIT") return false } }
// 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 }