Exemple #1
0
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
}
Exemple #2
0
// ----------------------------------------------------------------------------
// ---------------------    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
}
Exemple #3
0
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
}
Exemple #5
0
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.")
}
Exemple #6
0
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)
}
Exemple #7
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)
}
Exemple #8
0
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
}
Exemple #10
0
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)
}
Exemple #11
0
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

}
Exemple #12
0
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")
}
Exemple #13
0
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
}
Exemple #14
0
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
}
Exemple #15
0
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))
	}
}
Exemple #16
0
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
}
Exemple #17
0
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
}
Exemple #18
0
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
}
Exemple #19
0
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
}
Exemple #20
0
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)
}
Exemple #21
0
//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
}
Exemple #22
0
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)
}
Exemple #23
0
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
}
Exemple #24
0
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)
}
Exemple #25
0
//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
}
Exemple #27
0
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
}
Exemple #28
0
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
}
Exemple #29
0
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
}
Exemple #30
0
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")
}