func StartServicesAndChains(do *definitions.Do) error { // start the services and chains doSrvs := definitions.NowDo() if do.Action.Dependencies == nil || len(do.Action.Dependencies.Services) == 0 { log.Debug("No services to start") } else { doSrvs.Operations.Args = do.Action.Dependencies.Services log.WithField("args", doSrvs.Operations.Args).Debug("Starting services") if err := services.StartService(doSrvs); err != nil { return err } } doChns := definitions.NowDo() doChns.Name = do.Action.Chain if doChns.Name == "" { log.Debug("No chain to start") } else { log.WithField("=>", doChns.Name).Debug("Starting chain") if err := chains.StartChain(do); err != nil { return err } } return nil }
// Add a new entry (name) to the top of the HEAD file // Expects the chain type and head (id) to be full (already resolved) func ChangeHead(name string) error { if !IsKnownChain(name) && name != "" { log.Debug("Chain name not known. Not saving") return nil } log.Debug("Chain name known (or blank). Saving to head file") // read in the entire head file and clip // if we have reached the max length b, err := ioutil.ReadFile(common.HEAD) if err != nil { return err } bspl := strings.Split(string(b), "\n") var bsp string if len(bspl) >= MaxHead { bsp = strings.Join(bspl[:MaxHead-1], "\n") } else { bsp = string(b) } // add the new head var s string // handle empty head s = name + "\n" + bsp err = ioutil.WriteFile(common.HEAD, []byte(s), 0666) if err != nil { return err } log.Debug("Head file saved") return nil }
//------- helpers -------- func checkIPFSnotRunning() { //os.Setenv("ERIS_IPFS_HOST", "http://0.0.0.0") //conflicts with docker-machine do := def.NowDo() do.Known = false do.Existing = false do.Running = true do.Quiet = true log.Debug("Finding the running services") if err := list.ListAll(do, "services"); err != nil { IfExit(err) } res := strings.Split(do.Result, "\n") for _, r := range res { if r == "ipfs" { IfExit(fmt.Errorf("IPFS service is running.\nPlease stop it with.\neris services stop -rx ipfs\n")) } } // make sure ipfs container does not exist do = def.NowDo() do.Known = false do.Existing = true do.Running = false do.Quiet = true log.Debug("Finding the existing services") if err := list.ListAll(do, "services"); err != nil { IfExit(err) } res = strings.Split(do.Result, "\n") for _, r := range res { if r == "ipfs" { IfExit(fmt.Errorf("IPFS service exists.\nPlease remove it with\neris services rm ipfs\n")) } } }
// ---------------------------------------------------------------------------- // --------------------- Container Core ------------------------------------ // ---------------------------------------------------------------------------- func createContainer(opts docker.CreateContainerOptions) (*docker.Container, error) { dockerContainer, err := util.DockerClient.CreateContainer(opts) if err != nil { if err == docker.ErrNoSuchImage { if os.Getenv("ERIS_PULL_APPROVE") != "true" { var input string log.WithField("image", opts.Config.Image).Warn("The docker image not found locally") fmt.Print("Would you like the marmots to pull it from the repository? (y/n): ") fmt.Scanln(&input) if input == "Y" || input == "y" || input == "YES" || input == "Yes" || input == "yes" { log.Debug("User assented to pull") } else { log.Debug("User refused to pull") return nil, fmt.Errorf("Cannot start a container based on an image you will not let me pull.\n") } } else { log.WithField("image", opts.Config.Image).Warn("The Docker image is not found locally") log.Warn("The marmots are approved to pull it from the repository on your behalf") log.Warn("This could take a few minutes") } if err := pullImage(opts.Config.Image, nil); err != nil { return nil, err } dockerContainer, err = util.DockerClient.CreateContainer(opts) if err != nil { return nil, err } } else { return nil, err } } return dockerContainer, nil }
func StartService(do *definitions.Do) (err error) { var services []*definitions.ServiceDefinition do.Operations.Args = append(do.Operations.Args, do.ServicesSlice...) log.WithField("args", do.Operations.Args).Info("Building services group") for _, srv := range do.Operations.Args { s, e := BuildServicesGroup(srv, do.Operations.ContainerNumber) if e != nil { return e } services = append(services, s...) } // [csk]: controls for ops reconciliation, overwrite will, e.g., merge the maps and stuff for _, s := range services { util.Merge(s.Operations, do.Operations) } log.Debug("Preparing to build chain") for _, s := range services { log.WithFields(log.Fields{ "name": s.Name, "dependencies": s.Dependencies, "links": s.Service.Links, "volumes from": s.Service.VolumesFrom, }).Debug() // Spacer. log.Debug() } services, err = BuildChainGroup(do.ChainName, services) if err != nil { return err } log.Debug("Checking services after build chain") for _, s := range services { log.WithFields(log.Fields{ "name": s.Name, "dependencies": s.Dependencies, "links": s.Service.Links, "volumes from": s.Service.VolumesFrom, }).Debug() // Spacer. log.Debug() } // NOTE: the top level service should be at the end of the list topService := services[len(services)-1] topService.Service.Environment = append(topService.Service.Environment, do.Env...) topService.Service.Links = append(topService.Service.Links, do.Links...) services[len(services)-1] = topService return StartGroup(services) }
func getMachineDeets(machName string) (string, string, error) { var out = new(bytes.Buffer) var out2 = new(bytes.Buffer) noConnectError := fmt.Errorf("Could not evaluate the env vars for the %s docker-machine.\n", machName) dHost, dPath := popHostAndPath() if (dHost != "" && dPath != "") && (machName == "eris" || machName == "default") { return dHost, dPath, nil } // TODO: when go-dockerclient adds machine API endpoints use those instead. log.WithField("machine", machName).Debug("Querying Docker Machine URL") cmd := exec.Command("docker-machine", "url", machName) cmd.Stdout = out if err := cmd.Run(); err != nil { return "", "", fmt.Errorf("%vError:\t%v\n", noConnectError, err) } dHost = strings.TrimSpace(out.String()) log.WithField("host", dHost).Debug() // TODO: when go-dockerclient adds machine API endpoints use those instead. log.WithField("machine", machName).Debug("Querying Docker Machine cert path") cmd2 := exec.Command("docker-machine", "inspect", machName, "--format", "{{.HostOptions.AuthOptions.ServerCertPath}}") cmd2.Stdout = out2 //cmd2.Stderr = os.Stderr if err := cmd2.Run(); err != nil { return "", "", fmt.Errorf("%vError:\t%v\n", noConnectError, err) } dPath = out2.String() dPath = strings.Replace(dPath, "'", "", -1) dPath = filepath.Dir(dPath) log.WithField("cert path", dPath).Debug() if dPath == "" || dHost == "" { return "", "", noConnectError } log.Info("Querying host and user have access to the right files for TLS connection to Docker") if err := checkKeysAndCerts(dPath); err != nil { return "", "", err } log.Debug("Certificate files look good") // technically, do not *have* to do this, but it will make repetitive tasks faster log.Debug("Setting environment variables for quick future development") os.Setenv("DOCKER_HOST", dHost) os.Setenv("DOCKER_CERT_PATH", dPath) os.Setenv("DOCKER_TLS_VERIFY", "1") os.Setenv("DOCKER_MACHINE_NAME", machName) log.WithField("machine", machName).Debug("Finished getting machine details") return dHost, dPath, nil }
func setupErisMachine(driver string) error { cmd := "docker-machine" args := []string{"status", "eris"} if err := exec.Command(cmd, args...).Run(); err == nil { // if err == nil this means the machine is created. if err != nil that means machine doesn't exist. log.Debug("Eris Docker Machine exists. Starting") return startErisMachine() } log.Debug("Eris Docker Machine doesn't exist") return createErisMachine(driver) }
func readActionDefinition(actionName []string, dropped map[string]string, varNum int) (*viper.Viper, map[string]string, error) { if len(actionName) == 0 { log.WithFields(log.Fields{ "action": actionName, "drop": dropped, "var#": varNum, }).Debug("Failed to load action definition file") return nil, dropped, fmt.Errorf("The marmots could not find the action definition file.\nPlease check your actions with [eris actions ls]") } log.WithField("file", strings.Join(actionName, "_")).Debug("Preparing to read action definition file") log.WithField("drop", dropped).Debug() var actionConf = viper.New() actionConf.AddConfigPath(dir.ActionsPath) actionConf.SetConfigName(strings.Join(actionName, "_")) err := actionConf.ReadInConfig() if err != nil { log.WithField("action", actionName[len(actionName)-1]).Debug("Dropping and retrying") dropped[fmt.Sprintf("$%d", varNum)] = actionName[len(actionName)-1] actionName = actionName[:len(actionName)-1] varNum++ return readActionDefinition(actionName, dropped, varNum) } else { log.Debug("Successfully read action definition file") } return actionConf, dropped, nil }
func NewService(do *definitions.Do) error { srv := definitions.BlankServiceDefinition() srv.Name = do.Name srv.Service.Name = do.Name srv.Service.Image = do.Operations.Args[0] srv.Service.AutoData = true var err error //get maintainer info srv.Maintainer.Name, srv.Maintainer.Email, err = config.GitConfigUser() if err != nil { log.Debug(err.Error()) } log.WithFields(log.Fields{ "service": srv.Service.Name, "image": srv.Service.Image, }).Debug("Creating a new service definition file") err = WriteServiceDefinitionFile(srv, filepath.Join(ServicesPath, do.Name+".toml")) if err != nil { return err } do.Result = "success" return nil }
// this function is for parsing single variables func printField(container interface{}, field string) error { log.WithField("=>", field).Debug("Inspecting field") var line string // We allow fields to be passed using dot syntax, but // we have to make sure all fields are Camelized lineSplit := strings.Split(field, ".") for n, f := range lineSplit { lineSplit[n] = camelize(f) } FieldCamel := strings.Join(lineSplit, ".") f, _ := reflections.GetFieldKind(container, FieldCamel) log.Debug("Field type", f) switch f.String() { case "ptr": //we don't recurse into to gain a bit more control... this function will be rarely used and doesn't have to be perfectly parseable. case "map": line = fmt.Sprintf("{{ range $key, $val := .%v }}{{ $key }}->{{ $val }}\n{{ end }}\n", FieldCamel) case "slice": line = fmt.Sprintf("{{ range .%v }}{{ . }}\n{{ end }}\n", FieldCamel) default: line = fmt.Sprintf("{{.%v}}\n", FieldCamel) } return writeTemplate(container, line) }
//TODO test that this doesn't fmt things up, see note in #400 func moveOutOfDirAndRmDir(src, dest string) error { log.WithFields(log.Fields{ "from": src, "to": dest, }).Info("Move all files/dirs out of a dir and `rm -rf` that dir") toMove, err := filepath.Glob(filepath.Join(src, "*")) if err != nil { return err } if len(toMove) == 0 { log.Debug("No files to move") } for _, f := range toMove { // using a copy (read+write) strategy to get around swap partitions and other // problems that cause a simple rename strategy to fail. it is more io overhead // to do this, but for now that is preferable to alternative solutions. Copy(f, filepath.Join(dest, filepath.Base(f))) } log.WithField("=>", src).Info("Removing directory") err = os.RemoveAll(src) if err != nil { return err } return nil }
func ManagePinned(do *definitions.Do) error { ensureRunning() if do.Rm && do.Hash != "" { return fmt.Errorf("Either remove a file by hash or all of them\n") } if do.Rm { log.Info("Removing all cached files") hashes, err := rmAllPinned() if err != nil { return err } do.Result = hashes } else if do.Hash != "" { log.WithField("hash", do.Hash).Info("Removing from cache") hashes, err := rmPinnedByHash(do.Hash) if err != nil { return err } do.Result = hashes } else { log.Debug("Listing files pinned locally") hash, err := listPinned() if err != nil { return err } do.Result = hash } return nil }
func InstallEris() { goArgs := []string{"install", "./cmd/eris"} stdOut, err := exec.Command("go", goArgs...).CombinedOutput() if err != nil { log.Fatalf("Error with go install ./cmd/eris: %v", string(stdOut)) } log.Debug("Go install worked correctly") }
func startErisMachine() error { log.Info("Starting Eris Docker Machine") cmd := "docker-machine" args := []string{"start", "eris"} if err := exec.Command(cmd, args...).Run(); err != nil { return fmt.Errorf("There was an error starting the newly created docker-machine.\nError:\t%v\n", err) } log.Debug("Eris Docker Machine started") return nil }
func canWeMigrate() bool { fmt.Print("Permission to migrate deprecated directories required: would you like to continue? (Y/y): ") var input string fmt.Scanln(&input) if input == "Y" || input == "y" || input == "YES" || input == "Yes" || input == "yes" { log.Debug("Confirmation verified. Proceeding") return true } else { return false } }
func NewChain(do *definitions.Do) error { //overwrites directory if --force dir := filepath.Join(DataContainersPath, do.Name) if _, err := os.Stat(dir); err == nil { log.WithField("dir", dir).Debug("Chain data already exists in") if do.Force { log.Debug("Overwriting with new data") if os.RemoveAll(dir); err != nil { return err } } else { log.Debug("Using existing data; `--force` flag not given") } } // for now we just let setupChain force do.ChainID = do.Name // and we overwrite using jq in the container log.WithField("=>", do.Name).Debug("Setting up chain") return setupChain(do, loaders.ErisChainNew) }
func PortsService(do *definitions.Do) error { service, err := loaders.LoadServiceDefinition(do.Name, false, do.Operations.ContainerNumber) if err != nil { return err } if IsServiceExisting(service.Service, service.Operations) { log.Debug("Service exists, getting port mapping") return util.PrintPortMappings(service.Operations.SrvContainerID, do.Operations.Args) } return nil }
func createErisMachine(driver string) error { log.Warn("Creating the Eris Docker Machine") log.Warn("This will take some time, please feel free to go feed your marmot") log.WithField("driver", driver).Debug() cmd := "docker-machine" args := []string{"create", "--driver", driver, "eris"} if err := exec.Command(cmd, args...).Run(); err != nil { log.Debugf("There was an error creating the Eris Docker Machine: %v", err) return mustInstallError() } log.Debug("Eris Docker Machine created") return startErisMachine() }
func connectDockerTLS(dockerHost, dockerCertPath string) error { var err error log.WithFields(log.Fields{ "host": dockerHost, "cert path": dockerCertPath, }).Debug("Connecting to Docker via TLS") DockerClient, err = docker.NewTLSClient(dockerHost, filepath.Join(dockerCertPath, "cert.pem"), filepath.Join(dockerCertPath, "key.pem"), filepath.Join(dockerCertPath, "ca.pem")) if err != nil { return err } log.Debug("Connected via TLS") return nil }
func fixSteps(action *def.Action, dropReversed map[string]string) { log.Debug("Replacing $1, $2, $3 in steps with args from command line") if len(dropReversed) == 0 { return } else { log.WithField("replace", dropReversed).Debug() } // Because we pop from the end of the args list, the variables // in the map $1, $2, etc. are actually the exact opposite of // what they should be. dropped := make(map[string]string) j := 1 for i := len(dropReversed); i > 0; i-- { log.WithField("=>", fmt.Sprintf("$%d:$%d", i, j)).Debug("Reversing") dropped[fmt.Sprintf("$%d", j)] = dropReversed[fmt.Sprintf("$%d", i)] j++ } reg := regexp.MustCompile(`\$\d`) for n, step := range action.Steps { if reg.MatchString(step) { log.WithField("matched", step).Debug() for _, m := range reg.FindAllString(step, -1) { action.Steps[n] = strings.Replace(step, m, dropped[m], -1) } log.WithField("replaced", step).Debug() } } log.Debug("Checking fixed steps") for _, step := range action.Steps { log.WithField("step", step).Debug() } }
func CleanUp(do *definitions.Do) error { log.Info("Cleaning up") do.Force = true if do.Chain.ChainType == "throwaway" { log.WithField("=>", do.Chain.Name).Debug("Destroying throwaway chain") doRm := definitions.NowDo() doRm.Operations = do.Operations doRm.Name = do.Chain.Name doRm.Rm = true doRm.RmD = true doRm.Volumes = true KillChain(doRm) latentDir := filepath.Join(DataContainersPath, do.Chain.Name) latentFile := filepath.Join(ChainsPath, do.Chain.Name+".toml") if doRm.Name == "default" { log.WithField("dir", latentDir).Debug("Removing latent dir") os.RemoveAll(latentDir) } else { log.WithFields(log.Fields{ "dir": latentDir, "file": latentFile, }).Debug("Removing latent dir and file") os.RemoveAll(latentDir) os.Remove(latentFile) } } else { log.Debug("No throwaway chain to destroy") } if do.RmD { log.WithField("dir", filepath.Join(DataContainersPath, do.Service.Name)).Debug("Removing data dir on host") os.RemoveAll(filepath.Join(DataContainersPath, do.Service.Name)) } if do.Rm { log.WithField("=>", do.Operations.SrvContainerName).Debug("Removing tmp service container") perform.DockerRemove(do.Service, do.Operations, true, true, false) } return nil }
func RunPackage(do *definitions.Do) error { log.Debug("Welcome! Say the marmots. Running app package") var err error pwd, err = os.Getwd() if err != nil { return fmt.Errorf("Could not get the present working directory. Are you on Mars?\nError: %v\n", err) } log.WithFields(log.Fields{ "host path": do.Path, "pwd": pwd, }).Debug() app, err := loaders.LoadContractPackage(do.Path, do.ChainName, do.Name, do.Type) if err != nil { do.Result = "could not load package" return err } if err := BootServicesAndChain(do, app); err != nil { do.Result = "could not boot chain or services" CleanUp(do, app) return err } do.Path = pwd if err := DefineAppActionService(do, app); err != nil { do.Result = "could not define app action service" CleanUp(do, app) return err } if err := PerformAppActionService(do, app); err != nil { do.Result = "could not perform app action service" CleanUp(do, app) return err } do.Result = "success" return CleanUp(do, app) }
func cullCLIVariables(act []string) ([]string, []string) { var actionVars []string var action []string log.Debug("Pulling out named variables") for _, a := range act { if strings.Contains(a, ":") { r := strings.Replace(a, ":", "=", 1) actionVars = append(actionVars, r) log.WithField("=>", r).Debug("Culling from variable list") } else { action = append(action, a) } } log.Info("Successfully parsed named variables") log.WithFields(log.Fields{ "culled": actionVars, "not culled": action, }).Debug() return action, actionVars }
func fixChain(action *def.Action, chainName string) { // Steps can include a $chain variable which will be populated *solely* // the --chain flag which has been passed via the command line if chainName == "" { return } reg := regexp.MustCompile(`\$chain`) for n, step := range action.Steps { if reg.MatchString(step) { log.WithField("matched", step).Debug() for _, m := range reg.FindAllString(step, -1) { action.Steps[n] = strings.Replace(step, m, chainName, -1) } log.WithField("replaced", step).Debug() } } log.Debug("Checking fixed chain") for _, step := range action.Steps { log.WithField("step", step).Debug() } }
// marshal from viper to definitions struct func MarshalChainDefinition(chainConf *viper.Viper, chain *definitions.Chain) error { log.Debug("Marshalling chain") chnTemp := definitions.BlankChain() err := chainConf.Unmarshal(chnTemp) if err != nil { return fmt.Errorf("The marmots coult not marshal from viper to chain def: %v", err) } util.Merge(chain.Service, chnTemp.Service) chain.ChainID = chnTemp.ChainID // toml bools don't really marshal well // data_container can be in the chain or // in the service layer. this is very // opinionated. we know. for _, s := range []string{"", "service."} { if chainConf.GetBool(s + "data_container") { chain.Service.AutoData = true log.WithField("autodata", chain.Service.AutoData).Debug() } } return nil }
func PutFiles(do *definitions.Do) error { ensureRunning() if do.Gateway != "" { _, err := url.Parse(do.Gateway) if err != nil { return fmt.Errorf("Invalid gateway URL provided %v\n", err) } log.WithField("gateway", do.Gateway).Debug("Posting to") } else { log.Debug("Posting to gateway.ipfs.io") } if do.AddDir { log.WithFields(log.Fields{ "dir": do.Name, "gateway": do.Gateway, }).Debug("Adding contents of a directory") hashes, err := exportDir(do.Name, do.Gateway) if err != nil { return err } do.Result = hashes } else { log.WithFields(log.Fields{ "file": do.Name, "gateway": do.Gateway, }).Debug("Adding a file") hash, err := exportFile(do.Name, do.Gateway) if err != nil { return err } do.Result = hash } return nil }
//func askToPull removed since it's basically a duplicate of this func checkIfCanOverwrite(doYes bool) error { if doYes { return nil } var input string log.WithField("path", common.ErisRoot).Warn("Eris root directory already exists") log.WithFields(log.Fields{ "services path": common.ServicesPath, "actions path": common.ActionsPath, "chains path": common.ChainsPath, }).Warn("Continuing may overwrite files in:") fmt.Print("Do you wish to continue? (y/n): ") if _, err := fmt.Scanln(&input); err != nil { return fmt.Errorf("Error reading from stdin: %v\n", err) } if input == "Y" || input == "y" || input == "YES" || input == "Yes" || input == "yes" { log.Debug("Confirmation verified. Proceeding") } else { log.Warn("The marmots will not proceed without your permission to overwrite") log.Warn("Please backup your files and try again") return fmt.Errorf("Error:\tno permission given to overwrite services and actions\n") } return nil }
func CleanUp(do *definitions.Do, app *definitions.Contracts) error { log.Info("Cleaning up") if do.Chain.ChainType == "throwaway" { log.WithField("=>", do.Chain.Name).Debug("Destroying throwaway chain") doRm := definitions.NowDo() doRm.Operations = do.Operations doRm.Name = do.Chain.Name doRm.Rm = true doRm.RmD = true chains.KillChain(doRm) latentDir := filepath.Join(common.DataContainersPath, do.Chain.Name) latentFile := filepath.Join(common.ChainsPath, do.Chain.Name+".toml") log.WithFields(log.Fields{ "dir": latentDir, "file": latentFile, }).Debug("Removing latent dir and file") os.RemoveAll(latentDir) os.Remove(latentFile) } else { log.Debug("No throwaway chain to destroy") } doData := definitions.NowDo() doData.Name = do.Service.Name doData.Operations = do.Operations doData.Source = common.ErisContainerRoot if do.Path != pwd { doData.Destination = do.Path } else { doData.Destination = filepath.Join(common.DataContainersPath, doData.Name) } var loca string if do.Path != pwd { loca = filepath.Join(common.DataContainersPath, doData.Name, do.Path) } else { loca = filepath.Join(common.DataContainersPath, doData.Name, "apps", app.Name) } log.WithFields(log.Fields{ "path": doData.Source, "location": loca, }).Debug("Exporting results") data.ExportData(doData) if app.AppType.Name == "epm" { files, _ := filepath.Glob(filepath.Join(loca, "*")) for _, f := range files { dest := filepath.Join(do.Path, filepath.Base(f)) log.WithFields(log.Fields{ "from": f, "to": dest, }).Debug("Moving file") common.Copy(f, dest) } } if !do.RmD { log.WithField("dir", filepath.Join(common.DataContainersPath, do.Service.Name)).Debug("Removing data dir on host") os.RemoveAll(filepath.Join(common.DataContainersPath, do.Service.Name)) } if !do.Rm { doRemove := definitions.NowDo() doRemove.Operations.SrvContainerName = do.Operations.DataContainerName log.WithField("=>", doRemove.Operations.SrvContainerName).Debug("Removing data container") if err := perform.DockerRemove(nil, doRemove.Operations, false, true); err != nil { return err } } return nil }
func DefineAppActionService(do *definitions.Do, app *definitions.Contracts) error { var cmd string switch do.Name { case "test": cmd = app.AppType.TestCmd case "deploy": cmd = app.AppType.DeployCmd default: return fmt.Errorf("I do not know how to perform that task (%s)\nPlease check what you can do with contracts by typing [eris contracts].\n", do.Name) } // if manual, set task if app.AppType.Name == "manual" { switch do.Name { case "test": cmd = app.TestTask case "deploy": cmd = app.DeployTask } } // task flag override if do.Task != "" { app.AppType = definitions.GulpApp() cmd = do.Task } if cmd == "nil" { return fmt.Errorf("I cannot perform that task against that app type.\n") } // build service that will run do.Service.Name = app.Name + "_tmp_" + do.Name do.Service.Image = app.AppType.BaseImage do.Service.AutoData = true do.Service.EntryPoint = app.AppType.EntryPoint do.Service.Command = cmd if do.Path != pwd { do.Service.WorkDir = do.Path // do.Path is actually where the workdir inside the container goes } else { do.Service.WorkDir = filepath.Join(common.ErisContainerRoot, "apps", app.Name) } do.Service.User = "******" srv := definitions.BlankServiceDefinition() srv.Service = do.Service srv.Operations = do.Operations loaders.ServiceFinalizeLoad(srv) do.Service = srv.Service do.Operations = srv.Operations do.Operations.Follow = true linkAppToChain(do, app) if app.AppType.Name == "epm" { prepareEpmAction(do, app) } // make data container and import do.Path to do.Path (if exists) doData := definitions.NowDo() doData.Name = do.Service.Name doData.Operations = do.Operations if do.Path != pwd { doData.Destination = do.Path } else { doData.Destination = common.ErisContainerRoot } doData.Source = filepath.Join(common.DataContainersPath, doData.Name) var loca string if do.Path != pwd { loca = filepath.Join(common.DataContainersPath, doData.Name, do.Path) } else { loca = filepath.Join(common.DataContainersPath, doData.Name, "apps", app.Name) } log.WithFields(log.Fields{ "path": do.Path, "location": loca, }).Debug("Creating app data container") common.Copy(do.Path, loca) if err := data.ImportData(doData); err != nil { return err } do.Operations.DataContainerName = util.DataContainersName(doData.Name, doData.Operations.ContainerNumber) log.Debug("App action built") return nil }
// XXX: What's going on here? => [csk]: magic func RenameChain(do *definitions.Do) error { if do.Name == do.NewName { return fmt.Errorf("Cannot rename to same name") } newNameBase := strings.Replace(do.NewName, filepath.Ext(do.NewName), "", 1) transformOnly := newNameBase == do.Name if util.IsKnownChain(do.Name) { log.WithFields(log.Fields{ "from": do.Name, "to": do.NewName, }).Info("Renaming chain") log.WithField("=>", do.Name).Debug("Loading chain definition file") chainDef, err := loaders.LoadChainDefinition(do.Name, false, 1) // TODO:CNUM if err != nil { return err } if !transformOnly { log.Debug("Renaming chain container") err = perform.DockerRename(chainDef.Operations, do.NewName) if err != nil { return err } } oldFile := util.GetFileByNameAndType("chains", do.Name) if err != nil { return err } if filepath.Base(oldFile) == do.NewName { log.Info("Those are the same file. Not renaming") return nil } log.Debug("Renaming chain definition file") var newFile string if filepath.Ext(do.NewName) == "" { newFile = strings.Replace(oldFile, do.Name, do.NewName, 1) } else { newFile = filepath.Join(ChainsPath, do.NewName) } chainDef.Name = newNameBase // Generally we won't want to use Service.Name // as it will be confused with the Name. chainDef.Service.Name = "" // Service.Image should be taken from the default.toml. chainDef.Service.Image = "" err = WriteChainDefinitionFile(chainDef, newFile) if err != nil { return err } if !transformOnly { log.WithFields(log.Fields{ "from": fmt.Sprintf("%s:%d", do.Name, chainDef.Operations.ContainerNumber), "to": fmt.Sprintf("%s:%d", do.NewName, chainDef.Operations.ContainerNumber), }).Info("Renaming chain data container") do.Operations.ContainerNumber = chainDef.Operations.ContainerNumber err = data.RenameData(do) if err != nil { return err } } os.Remove(oldFile) } else { return fmt.Errorf("I cannot find that chain. Please check the chain name you sent me.") } return nil }