func GetTheImages() error { if os.Getenv("ERIS_PULL_APPROVE") == "true" { if err := pullDefaultImages(); err != nil { return err } log.Warn("Pulling of default images successful") } else { var input string log.Warn(`WARNING: Approximately 1 gigabyte of docker images are about to be pulled onto your host machine Please ensure that you have sufficient bandwidth to handle the download On a remote host in the cloud, this should only take a few minutes but can sometimes take 10 or more. These times can double or triple on local host machines If you already have these images, they will be updated`) log.WithField("ERIS_PULL_APPROVE", "true").Warn("To avoid this warning on all future pulls, set as an environment variable") 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" { if err := pullDefaultImages(); err != nil { return err } log.Warn("Pulling of default images successful") } } return nil }
// ---------------------------------------------------------------------------- // --------------------- 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 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() }
//XXX chains and services only func ListAll(do *definitions.Do, typ string) (err error) { quiet := do.Quiet var result string if do.All == true { //overrides all the functionality used for flags/tests to stdout a nice table resK, err := ListKnown(typ) if err != nil { return err } do.Result = resK //for testing but not rly needed knowns := strings.Split(resK, "\n") typs := fmt.Sprintf("The known %s on your host kind marmot:", typ) log.WithField("=>", knowns[0]).Warn(typs) knowns = append(knowns[:0], knowns[1:]...) for _, known := range knowns { log.WithField("=>", known).Warn() } result, err = PrintTableReport(typ, true, true) //when latter bool is true, former one will be ignored... if err != nil { return err } contType := fmt.Sprintf("Active %s containers:", typ) log.Warn(contType) log.Warn(result) } else { var resK, resR, resE string if do.Known { if resK, err = ListKnown(typ); err != nil { return err } do.Result = resK } if do.Running { if resR, err = ListRunningOrExisting(quiet, false, typ); err != nil { return err } do.Result = resR } if do.Existing { if resE, err = ListRunningOrExisting(quiet, true, typ); err != nil { return err } do.Result = resE } } return nil }
func ImportChain(do *definitions.Do) error { fileName := filepath.Join(ChainsPath, do.Name) if filepath.Ext(fileName) == "" { fileName = fileName + ".toml" } s := strings.Split(do.Path, ":") if s[0] == "ipfs" { var err error if log.GetLevel() > 0 { err = ipfs.GetFromIPFS(s[1], fileName, "", os.Stdout) } else { err = ipfs.GetFromIPFS(s[1], fileName, "", bytes.NewBuffer([]byte{})) } if err != nil { return err } return nil } if strings.Contains(s[0], "github") { log.Warn("https://twitter.com/ryaneshea/status/595957712040628224") return nil } return fmt.Errorf("I do not know how to get that file. Sorry.") }
func TestKillRmService(t *testing.T) { testStartService(t, servName, false) do := def.NowDo() do.Name = servName do.Rm = false do.RmD = false do.Operations.Args = []string{servName} log.WithField("=>", servName).Debug("Stopping service (from tests)") if e := KillService(do); e != nil { log.Error(e) tests.IfExit(e) } testExistAndRun(t, servName, 1, true, false) testNumbersExistAndRun(t, servName, 1, 0) if os.Getenv("TEST_IN_CIRCLE") == "true" { log.Warn("Testing in Circle where we don't have rm privileges. Skipping test") return } do = def.NowDo() do.Name = servName do.Operations.Args = []string{servName} do.File = false do.RmD = true log.WithField("=>", servName).Debug("Removing service (from tests)") if e := RmService(do); e != nil { log.Error(e) tests.IfExit(e) } testExistAndRun(t, servName, 1, false, false) testNumbersExistAndRun(t, servName, 0, 0) }
func FilesPut(cmd *cobra.Command, args []string) { IfExit(ArgCheck(1, "eq", cmd, args)) do.Name = args[0] err := files.PutFiles(do) IfExit(err) log.Warn(do.Result) }
func ImportAction(do *definitions.Do) error { if do.Name == "" { do.Name = strings.Join(do.Operations.Args, "_") } fileName := filepath.Join(ActionsPath, strings.Join(do.Operations.Args, " ")) if filepath.Ext(fileName) == "" { fileName = fileName + ".toml" } s := strings.Split(do.Path, ":") if s[0] == "ipfs" { var err error //unset 1 as default ContainerNumber, let it take flag? ipfsService, err := loaders.LoadServiceDefinition("ipfs", false, 1) if err != nil { return err } ipfsService.Operations.ContainerType = definitions.TypeService err = perform.DockerRunService(ipfsService.Service, ipfsService.Operations) if err != nil { return err } if log.GetLevel() > 0 { err = ipfs.GetFromIPFS(s[1], fileName, "", os.Stdout) } else { err = ipfs.GetFromIPFS(s[1], fileName, "", bytes.NewBuffer([]byte{})) } if err != nil { return err } return nil } if strings.Contains(s[0], "github") { log.Warn("https://twitter.com/ryaneshea/status/595957712040628224") return nil } log.Warn("Failed to get that file. Sorry") return nil }
// pulled out for simplicity; neither known or running func ListDatas(do *definitions.Do) error { var result string var err error if do.Quiet { result = strings.Join(util.DataContainerNames(), "\n") do.Result = result log.Warn(result) } else { result, err = PrintTableReport("data", true, true) if err != nil { return err } log.Warn("Active data containers:") log.Warn(result) } return nil }
func FilesList(cmd *cobra.Command, args []string) { if len(args) != 1 { cmd.Help() return } do.Name = args[0] err := files.ListFiles(do) IfExit(err) log.Warn(do.Result) }
func CatChain(do *definitions.Do) error { cat, err := ioutil.ReadFile(filepath.Join(ChainsPath, do.Name+".toml")) if err != nil { return err } // Let's actually WRITE this to the GlobalConfig.Writer... log.Warn(string(cat)) return nil }
func TestPutFiles(t *testing.T) { do := definitions.NowDo() do.Name = file log.WithField("=>", do.Name).Info("Putting file (from tests)") hash := "QmcJdniiSKMp5az3fJvkbJTANd7bFtDoUkov3a8pkByWkv" // Fake IPFS server. os.Setenv("ERIS_IPFS_HOST", "http://0.0.0.0") ipfs := tests.NewServer("0.0.0.0:8080") log.Warn("Server turned on.") ipfs.SetResponse(tests.ServerResponse{ Code: http.StatusOK, Header: map[string][]string{ "Ipfs-Hash": {hash}, }, }) log.Warn("Waiting on server response.") defer ipfs.Close() if err := PutFiles(do); err != nil { fatal(t, err) } if expected := "/ipfs/"; ipfs.Path() != expected { fatal(t, fmt.Errorf("Called the wrong endpoint; expected %v, got %v\n", expected, ipfs.Path())) } if expected := "POST"; ipfs.Method() != expected { fatal(t, fmt.Errorf("Used the wrong HTTP method; expected %v, got %v\n", expected, ipfs.Method())) } if ipfs.Body() != content { fatal(t, fmt.Errorf("Put the bad file; expected %q, got %q\n", content, ipfs.Body())) } if hash != do.Result { fatal(t, fmt.Errorf("Hash mismatch; expected %q, got %q\n", hash, do.Result)) } log.WithField("result", do.Result).Debug("Finished putting a file") }
func checkThenInitErisRoot(force bool) (bool, error) { var newDir bool if force { //for testing only log.Warn("Force initializing eris root directory") if err := common.InitErisDir(); err != nil { return true, fmt.Errorf("Error:\tcould not initialize the eris root directory.\n%s\n", err) } return true, nil } if !util.DoesDirExist(common.ErisRoot) { log.Warn("Eris root directory does not exist. The marmots will initialize this directory for you") if err := common.InitErisDir(); err != nil { return true, fmt.Errorf("Error:\tcould not initialize the eris root directory.\n%s\n", err) } newDir = true } else { // ErisRoot exists, prompt for overwrite newDir = false } return newDir, nil }
func removeErisImages(prompt bool) error { opts := docker.ListImagesOptions{ All: true, Filters: nil, Digests: false, } allTheImages, err := DockerClient.ListImages(opts) if err != nil { return err } //get all repo tags & IDs // [zr] this could probably be cleaner repoTags := make(map[int][]string) imageIDs := make(map[int]string) for i, image := range allTheImages { repoTags[i] = image.RepoTags imageIDs[i] = image.ID } erisImages := []string{} erisImageIDs := []string{} //searches through repo tags for eris images & "maps" to ID for i, repoTag := range repoTags { for _, rt := range repoTag { r, err := regexp.Compile(`eris`) if err != nil { log.Errorf("Regexp error: %v", err) } if r.MatchString(rt) == true { erisImages = append(erisImages, rt) erisImageIDs = append(erisImageIDs, imageIDs[i]) } } } if !prompt || canWeRemove(erisImages, "images") { for i, imageID := range erisImageIDs { log.WithFields(log.Fields{ "=>": erisImages[i], "id": imageID, }).Debug("Removing image") if err := DockerClient.RemoveImage(imageID); err != nil { return err } } } else { log.Warn("Permission to remove images not given, continuing with clean") } return nil }
func ListActions(cmd *cobra.Command, args []string) { // TODO: add scoping for when projects done. do.Known = true do.Running = false do.Existing = false if err := util.ListAll(do, "actions"); err != nil { return } for _, s := range strings.Split(do.Result, "\n") { log.Warn(strings.Replace(s, "_", " ", -1)) } }
func CurrentChain(do *definitions.Do) error { head, _ := util.GetHead() if head == "" { head = "There is no chain checked out." } log.Warn(head) do.Result = head return nil }
func Initialize(do *definitions.Do) error { log.Warn("Checking for eris root directory") //do.Quiet forces a new dir, only used for testing newDir, err := checkThenInitErisRoot(do.Quiet) if err != nil { return err } if !newDir { //new ErisRoot won't have either...can skip if err := checkIfCanOverwrite(do.Yes); err != nil { return err } log.Warn("Checking if migration is required") if err := checkIfMigrationRequired(do.Yes); err != nil { return err } } if do.Pull { //true by default; if imgs already exist, will check for latest anyways if err := GetTheImages(); err != nil { return err } } //drops: services, actions, & chain defaults from toadserver log.Warn("Initializing defaults") if err := InitDefaults(do, newDir); err != nil { return fmt.Errorf("Error:\tcould not instantiate default services.\n%s\n", err) } //TODO: when called from cli provide option to go on tour, like `ipfs tour` //[zr] this'll be cleaner with `make` log.Warn("The marmots have everything set up for you") log.Warn("If you are just getting started please type [eris] to get an overview of the tool") return nil }
func pullDefaultImages() error { images := []string{ ver.ERIS_IMG_BASE, ver.ERIS_IMG_DATA, ver.ERIS_IMG_KEYS, ver.ERIS_IMG_IPFS, ver.ERIS_IMG_DB, ver.ERIS_IMG_PM, ver.ERIS_IMG_CM, } log.Warn("Pulling default docker images from quay.io") // XXX can't use perform.PullImage b/c import cycle :( // it's essentially re-implemented here w/ a bit more opinion // fail over to docker hub is quay is down/firewalled auth := docker.AuthConfiguration{} for _, image := range images { var tag string = "latest" nameSplit := strings.Split(image, ":") if len(nameSplit) == 2 { tag = nameSplit[1] } if len(nameSplit) == 3 { tag = nameSplit[2] } image = nameSplit[0] img := path.Join(ver.ERIS_REG_DEF, image) opts := docker.PullImageOptions{ Repository: img, Registry: ver.ERIS_REG_DEF, Tag: tag, OutputStream: os.Stdout, } if os.Getenv("ERIS_PULL_APPROVE") == "true" { opts.OutputStream = nil } if err := util.DockerClient.PullImage(opts, auth); err != nil { //try with hub (empty string) opts.Repository = image opts.Registry = ver.ERIS_REG_BAK if err := util.DockerClient.PullImage(opts, auth); err != nil { return err } } } return nil }
func PerformCommand(action *definitions.Action, actionVars []string, quiet bool) error { log.WithField("action", action.Name).Info("Performing action") dir, err := os.Getwd() if err != nil { return err } log.WithField("directory", dir).Debug() // pull actionVars (first given from command line) and // combine with the environment variables (given in the // action definition files) and finally combine with // the hosts os.Environ() to provide the full set of // variables to be consumed during the steps phase. for k, v := range action.Environment { actionVars = append(actionVars, fmt.Sprintf("%s=%s", k, v)) } for _, v := range actionVars { log.WithField("variable", v).Debug() } actionVars = append(os.Environ(), actionVars...) for n, step := range action.Steps { cmd := exec.Command("sh", "-c", step) if runtime.GOOS == "windows" { cmd = exec.Command("cmd", "/c", step) } cmd.Env = actionVars cmd.Dir = dir log.WithField("=>", strings.Join(cmd.Args, " ")).Debugf("Performing step %d", n+1) prev, err := cmd.Output() if err != nil { return fmt.Errorf("error running command (%v): %s", err, prev) } if !quiet { log.Warn(strings.TrimSpace(string(prev))) } if n != 0 { actionVars = actionVars[:len(actionVars)-1] } actionVars = append(actionVars, ("prev=" + strings.TrimSpace(string(prev)))) } log.Info("Action performed") return nil }
func FilesPin(cmd *cobra.Command, args []string) { if do.CSV == "" { if len(args) != 1 { cmd.Help() return } do.Name = args[0] } else { do.Name = "" } err := files.PinFiles(do) IfExit(err) log.Warn(do.Result) }
//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 CatService(do *definitions.Do) error { configs := util.GetGlobalLevelConfigFilesByType("services", true) for _, c := range configs { cName := strings.Split(filepath.Base(c), ".")[0] if cName == do.Name { cat, err := ioutil.ReadFile(c) if err != nil { return err } do.Result = string(cat) log.Warn(string(cat)) return nil } } return fmt.Errorf("Unknown service %s or invalid file extension", do.Name) }
func PrintPortMappings(id string, ports []string) error { cont, err := DockerClient.InspectContainer(id) if err != nil { return err } exposedPorts := cont.NetworkSettings.Ports var minimalDisplay bool if len(ports) == 1 { minimalDisplay = true } // Display everything if no port's requested. if len(ports) == 0 { for exposed := range exposedPorts { ports = append(ports, string(exposed)) } } // Replace plain port numbers without suffixes with both "/tcp" and "/udp" suffixes. // (For example, replace ["53"] in a slice with ["53/tcp", "53/udp"].) normalizedPorts := []string{} for _, port := range ports { if !strings.HasSuffix(port, "/tcp") && !strings.HasSuffix(port, "/udp") { normalizedPorts = append(normalizedPorts, port+"/tcp", port+"/udp") } else { normalizedPorts = append(normalizedPorts, port) } } for _, port := range normalizedPorts { for _, binding := range exposedPorts[docker.Port(port)] { hostAndPortBinding := fmt.Sprintf("%s:%s", binding.HostIP, binding.HostPort) // If only one port request, display just the binding. if minimalDisplay { log.Warn(hostAndPortBinding) } else { log.Warnf("%s -> %s", port, hostAndPortBinding) } } } return nil }
func testKillDataCont(t *testing.T, name string) { if os.Getenv("TEST_IN_CIRCLE") == "true" { log.Warn("Testing in Circle. Where we don't have rm privileges. Skipping test") return } testCreateDataByImport(t, name) testExist(t, name, true) do := definitions.NowDo() do.Name = name do.Operations.ContainerNumber = 1 if err := RmData(do); err != nil { log.Error(err) t.Fail() } testExist(t, name, false) }
//XXX this command absolutely needs a good test!! func MigrateDeprecatedDirs(dirsToMigrate map[string]string, prompt bool) error { dirsMap, isMigNeed := dirCheckMaker(dirsToMigrate) if isMigNeed { log.Warn("Deprecated directories detected. Marmot migration commencing") } if !isMigNeed { log.Info("Nothing to migrate") return nil } else if !prompt { return Migrate(dirsMap) } else if canWeMigrate() { return Migrate(dirsMap) } else { return fmt.Errorf("permission to migrate not given") } return nil }
func ListActions(do *definitions.Do) error { actions, err := ListKnown("actions") if err != nil { return err } if do.Quiet { do.Result = actions //for testing but not rly needed log.Warn(actions) } else { knowns := strings.Split(actions, "\n") log.WithField("=>", knowns[0]).Warn("The known actions on your host kind marmot:") knowns = append(knowns[:0], knowns[1:]...) for _, known := range knowns { log.WithField("=>", known).Warn() } } return nil }
func PerformAppActionService(do *definitions.Do, app *definitions.Contracts) error { log.Warn("Performing action. This can sometimes take a wee while") log.WithFields(log.Fields{ "service": do.Service.Name, "image": do.Service.Image, }).Info() log.WithFields(log.Fields{ "workdir": do.Service.WorkDir, "entrypoint": do.Service.EntryPoint, }).Debug() do.Operations.ContainerType = definitions.TypeService if err := perform.DockerExecService(do.Service, do.Operations); err != nil { do.Result = "could not perform app action" return err } log.Info("Finished performing app action") return nil }
func canWeRemove(removing []string, what string) bool { //if nothing in removing, say so and return, or something var input string if what == "all" { fmt.Print("The marmots are about to forcefully remove all running and existing eris containers with corresponding volumes. Please confirm (y/Y): ") } else { log.WithField("=>", what).Warn("The marmots are about to remove") log.Warn(strings.Join(removing, "\n")) fmt.Print("Please confirm (y/Y): ") } fmt.Scanln(&input) if input == "Y" || input == "y" || input == "YES" || input == "Yes" || input == "yes" { log.WithField("=>", what).Warn("Authorization given, removing") return true } else { return false } return false }
func removeErisDir(prompt bool) error { erisRoot, err := ioutil.ReadDir(ErisRoot) if err != nil { return err } dirsInErisRoot := make([]string, len(erisRoot)) for i, dir := range erisRoot { dirsInErisRoot[i] = dir.Name() } if !prompt || canWeRemove(dirsInErisRoot, ErisRoot) { if err := os.RemoveAll(ErisRoot); err != nil { return err } } else { log.Warn("Permission to remove eris root directory not given, continuing with clean") } return nil }
func UpdateEris(branch string, checkGit bool, checkGo bool) { //check that git/go are installed hasGit, hasGo := CheckGitAndGo(checkGit, checkGo) if hasGo == false { log.Println("Go is not installed. Downloading eris-cli binary...") _, err := downloadLatestRelease() if err != nil { log.Println("Latest binary failed to download with error:", err) log.Println("Exiting...") os.Exit(1) } } else if hasGit == false { log.Println("Git is not installed. Please install git before continuing.") log.Println("Exiting...") os.Exit(1) } //checks for deprecated dir names and renames them err := MigrateDeprecatedDirs(common.DirsToMigrate, false) // false = no prompt if err != nil { log.Warnf("Directory migration error: %v", err) log.Warn("Continuing with update without migration") } //change pwd to eris/cli ChangeDirectory("src") if branch == "" { branch = "master" } CheckoutBranch(branch) PullBranch(branch) InstallEris() ver := version() //because version.Version will be in RAM. log.WithField("=>", ver).Warn("The marmots have updated Eris successfully") }