func giveMeAllTheNames(name string, srv *def.ServiceDefinition) { logger.Debugf("Giving myself all the names =>\t%s\n", name) srv.Name = name srv.Service.Name = name srv.Operations.SrvContainerName = util.DataContainersName(srv.Name, srv.Operations.ContainerNumber) srv.Operations.DataContainerName = util.DataContainersName(srv.Name, srv.Operations.ContainerNumber) logger.Debugf("My service container name is =>\t%s\n", srv.Operations.SrvContainerName) logger.Debugf("My data container name is =>\t%s\n", srv.Operations.DataContainerName) }
func giveMeAllTheNames(name string, srv *def.ServiceDefinition) { log.WithField("=>", name).Debug("Giving myself all the names") srv.Name = name srv.Service.Name = name srv.Operations.SrvContainerName = util.DataContainersName(srv.Name, srv.Operations.ContainerNumber) srv.Operations.DataContainerName = util.DataContainersName(srv.Name, srv.Operations.ContainerNumber) log.WithFields(log.Fields{ "data container": srv.Operations.DataContainerName, "service container": srv.Operations.SrvContainerName, }).Debug("Using names") }
func testExist(t *testing.T, name string, toExist bool) { var exist bool logger.Infof("\nTesting whether (%s) existing? (%t)\n", name, toExist) name = util.DataContainersName(name, 1) do := definitions.NowDo() do.Quiet = true if err := ListKnown(do); err != nil { logger.Errorln(err) t.FailNow() } res := strings.Split(do.Result, "\n") for _, r := range res { logger.Debugf("Existing =>\t\t\t%s\n", r) if r == util.ContainersShortName(name) { exist = true } } if toExist != exist { if toExist { logger.Infof("Could not find an existing =>\t%s\n", name) } else { logger.Infof("Found an existing instance of %s when I shouldn't have\n", name) } t.Fail() } }
// LoadDataDefinition returns an Operation structure for a blank data container // specified by a name dataName and a cNum number. func LoadDataDefinition(dataName string, cNum int) *definitions.Operation { if cNum == 0 { cNum = 1 } log.WithField("=>", fmt.Sprintf("%s:%d", dataName, cNum)).Debug("Loading data definition") ops := definitions.BlankOperation() ops.ContainerNumber = cNum ops.ContainerType = definitions.TypeData ops.SrvContainerName = util.DataContainersName(dataName, cNum) ops.DataContainerName = util.DataContainersName(dataName, cNum) ops.Labels = util.Labels(dataName, ops) return ops }
// LoadDataDefinition returns an Operation structure for a blank data container // specified by a name dataName and a cNum number. func LoadDataDefinition(dataName string, cNum int) *definitions.Operation { if cNum == 0 { cNum = 1 } logger.Debugf("Loading Data Definition =>\t%s:%d\n", dataName, cNum) ops := definitions.BlankOperation() ops.ContainerNumber = cNum ops.ContainerType = definitions.TypeData ops.SrvContainerName = util.DataContainersName(dataName, cNum) ops.DataContainerName = util.DataContainersName(dataName, cNum) ops.Labels = util.Labels(dataName, ops) return ops }
// ImportData does what it says. It imports from a host's Source to a Dest // in a data container. It returns an error. // // do.Name - name of the data container to use (required) // do.Operations.ContainerNumber - container number (optional) // do.Source - directory which should be imported (required) // do.Destination - directory to _unload_ the payload into (required) // func ImportData(do *definitions.Do) error { log.WithFields(log.Fields{ "from": do.Source, "to": do.Destination, }).Debug("Importing") if util.IsDataContainer(do.Name, do.Operations.ContainerNumber) { srv := PretendToBeAService(do.Name, do.Operations.ContainerNumber) service, exists := perform.ContainerExists(srv.Operations) if !exists { return fmt.Errorf("There is no data container for that service.") } if err := checkErisContainerRoot(do, "import"); err != nil { return err } containerName := util.DataContainersName(do.Name, do.Operations.ContainerNumber) os.Chdir(do.Source) reader, err := util.Tar(do.Source, 0) if err != nil { return err } defer reader.Close() opts := docker.UploadToContainerOptions{ InputStream: reader, Path: do.Destination, NoOverwriteDirNonDir: true, } log.WithField("=>", containerName).Info("Copying into container") log.WithField("path", do.Source).Debug() if err := util.DockerClient.UploadToContainer(service.ID, opts); err != nil { return err } doChown := definitions.NowDo() doChown.Operations.DataContainerName = containerName doChown.Operations.ContainerType = "data" doChown.Operations.ContainerNumber = do.Operations.ContainerNumber //required b/c `docker cp` (UploadToContainer) goes in as root doChown.Operations.Args = []string{"chown", "--recursive", "eris", do.Destination} _, err = perform.DockerRunData(doChown.Operations, nil) if err != nil { return fmt.Errorf("Error changing owner: %v\n", err) } } else { log.WithField("name", do.Name).Info("Data container does not exist.") ops := loaders.LoadDataDefinition(do.Name, do.Operations.ContainerNumber) if err := perform.DockerCreateData(ops); err != nil { return fmt.Errorf("Error creating data container %v.", err) } return ImportData(do) } do.Result = "success" return nil }
func ImportData(do *definitions.Do) error { if util.IsDataContainer(do.Name, do.Operations.ContainerNumber) { srv := PretendToBeAService(do.Name, do.Operations.ContainerNumber) service, exists := perform.ContainerExists(srv.Operations) if !exists { return fmt.Errorf("There is no data container for that service.") } containerName := util.DataContainersName(do.Name, do.Operations.ContainerNumber) logger.Debugf("Importing FROM =>\t\t%s\n", do.Source) os.Chdir(do.Source) logger.Debugf("Importing TO =>\t\t\t%s\n", do.Destination) reader, err := util.Tar(do.Source, 0) if err != nil { return err } defer reader.Close() opts := docker.UploadToContainerOptions{ InputStream: reader, Path: do.Destination, NoOverwriteDirNonDir: true, } logger.Infof("Copying into Cont. ID =>\t%s\n", service.ID) logger.Debugf("\tPath =>\t\t\t%s\n", do.Source) if err := util.DockerClient.UploadToContainer(service.ID, opts); err != nil { return err } doChown := definitions.NowDo() doChown.Operations.DataContainerName = containerName doChown.Operations.ContainerType = "data" doChown.Operations.ContainerNumber = 1 doChown.Operations.Args = []string{"chown", "--recursive", "eris", do.Destination} _, err = perform.DockerRunData(doChown.Operations, nil) if err != nil { return fmt.Errorf("Error changing owner: %v\n", err) } } else { ops := loaders.LoadDataDefinition(do.Name, do.Operations.ContainerNumber) if err := perform.DockerCreateData(ops); err != nil { return fmt.Errorf("Error creating data container %v.", err) } return ImportData(do) } do.Result = "success" return nil }
func ExecData(do *definitions.Do) error { if util.IsDataContainer(do.Name, do.Operations.ContainerNumber) { do.Name = util.DataContainersName(do.Name, do.Operations.ContainerNumber) logger.Infoln("Running exec on container with volumes from data container " + do.Name) if err := perform.DockerRunVolumesFromContainer(do.Name, do.Interactive, do.Args); err != nil { return err } } else { return fmt.Errorf("I cannot find that data container. Please check the data container name you sent me.") } do.Result = "success" return nil }
func RegisterChain(do *definitions.Do) error { // do.Name is mandatory if do.Name == "" { return fmt.Errorf("RegisterChain requires a chainame") } etcbChain := do.ChainID do.ChainID = do.Name // NOTE: registration expects you to have the data container if !data.IsKnown(do.Name) { return fmt.Errorf("Registration requires you to have a data container for the chain. Could not find data for %s", do.Name) } chain, err := loaders.LoadChainDefinition(do.Name, false, do.Operations.ContainerNumber) if err != nil { return err } logger.Debugf("Chain Loaded. Image =>\t\t%v\n", chain.Service.Image) // set chainid and other vars envVars := []string{ fmt.Sprintf("CHAIN_ID=%s", do.ChainID), // of the etcb chain fmt.Sprintf("PUBKEY=%s", do.Pubkey), // pubkey to register chain with fmt.Sprintf("ETCB_CHAIN_ID=%s", etcbChain), // chain id of the etcb chain fmt.Sprintf("NODE_ADDR=%s", do.Gateway), // etcb node to send the register tx to fmt.Sprintf("NEW_P2P_SEEDS=%s", do.Args[0]), // seeds to register for the chain // TODO: deal with multi seed (needs support in tendermint) } envVars = append(envVars, do.Env...) logger.Debugf("Set env vars from RegisterChain =>\t%v\n", envVars) chain.Service.Environment = append(chain.Service.Environment, envVars...) logger.Debugf("Set links from RegisterChain =>\t%v\n", do.Links) chain.Service.Links = append(chain.Service.Links, do.Links...) if err := bootDependencies(chain, do); err != nil { return err } logger.Debugf("Starting chain container via Docker =>\t%s\n", chain.Service.Name) logger.Debugf("\twith Image =>\t\t%s\n", chain.Service.Image) cmd := []string{loaders.ErisChainRegister} dataContainerName := util.DataContainersName(chain.Name, chain.Operations.ContainerNumber) _, err = perform.DockerRunVolumesFromContainer(dataContainerName, false, cmd, chain.Service) return err }
// eris chains new -c _ -csv _ func TestChainsNewConfigAndCSV(t *testing.T) { chainID := "testChainsNewConfigAndCSV" do := def.NowDo() do.Name = chainID do.ConfigFile = path.Join(common.BlockchainsPath, "config", "default", "config.toml") do.CSV = path.Join(common.BlockchainsPath, "config", "default", "genesis.csv") do.Operations.ContainerNumber = 1 logger.Infof("Creating chain (from tests) =>\t%s\n", do.Name) ifExit(NewChain(do)) b, err := ioutil.ReadFile(do.ConfigFile) if err != nil { fatal(t, err) } fmt.Println("CONFIG CONFIG CONFIG:", string(b)) // remove the data container defer removeDataContainer(t, chainID, do.Operations.ContainerNumber) // verify the contents of config.toml do.Name = util.DataContainersName(do.Name, do.Operations.ContainerNumber) args := []string{"cat", fmt.Sprintf("/home/eris/.eris/blockchains/%s/config.toml", chainID)} result := trimResult(string(runContainer(t, do.Name, args))) contents := trimResult(ini.DefChainConfig()) if result != contents { fatal(t, fmt.Errorf("config not properly copied. Got: %s \n Expected: %s", result, contents)) } // verify the contents of genesis.json (should have the validator from the csv) args = []string{"cat", fmt.Sprintf("/home/eris/.eris/blockchains/%s/genesis.json", chainID)} result = string(runContainer(t, do.Name, args)) var found bool for _, s := range strings.Split(result, "\n") { if strings.Contains(s, ini.DefaultPubKeys[0]) { found = true break } } if !found { fatal(t, fmt.Errorf("Did not find pubkey %s in genesis.json: %s", ini.DefaultPubKeys[0], result)) } }
func ImportData(do *definitions.Do) error { if util.IsDataContainer(do.Name, do.Operations.ContainerNumber) { containerName := util.DataContainersName(do.Name, do.Operations.ContainerNumber) importPath := filepath.Join(DataContainersPath, do.Name) // temp until docker cp works both ways. logger.Debugf("Importing FROM =>\t\t%s\n", importPath) os.Chdir(importPath) // TODO [eb]: deal with hardcoded user // TODO [csk]: drop the whole damn cmd call // use go's tar lib to make a tarball of the directory // read the tar file into an io.Reader // start a container with its Stdin open, connect to an io.Writer // connect them up with io.Pipe // this will free us from any quirks that the cli has if do.Path != "" { do.Path = do.Path } else { do.Path = "/home/eris/.eris" } logger.Debugf("Importing TO =>\t\t\t%s\n", do.Path) cmd := "tar chf - . | docker run -i --rm --volumes-from " + containerName + " --user eris eris/data tar xf - -C " + do.Path _, err := pipes.RunString(cmd) if err != nil { cmd := "tar chf - . | docker run -i --volumes-from " + containerName + " --user eris eris/data tar xf - -C " + do.Path _, e2 := pipes.RunString(cmd) if e2 != nil { return fmt.Errorf("Could not import the data container.\nTried with docker --rm =>\t%v\nTried without docker --rm =>\t%v", err, e2) } } } else { if err := perform.DockerCreateDataContainer(do.Name, do.Operations.ContainerNumber); err != nil { return fmt.Errorf("Error creating data container %v.", err) } return ImportData(do) } do.Result = "success" return nil }
// Build against Docker cli... // Client version: 1.6.2, 1.7 // Client API version: 1.18, 1.19 // Verified against ... // Client version: 1.6.2, 1.7 // Client API version: 1.18, 1.19 func DockerCreateDataContainer(srvName string, containerNumber int) error { logger.Infof("Creating Data Container for =>\t%s\n", srvName) srv := def.BlankServiceDefinition() srv.Operations.DataContainerName = util.DataContainersName(srvName, containerNumber) optsData, err := configureDataContainer(srv.Service, srv.Operations, nil) if err != nil { return err } srv.Operations.SrvContainerName = srv.Operations.DataContainerName // mock for the query function if _, exists := ContainerExists(srv.Operations); exists { logger.Infoln("Data container exists. Not creating.") return nil } cont, err := createContainer(optsData) if err != nil { return err } logger.Infof("Data Container ID =>\t\t%s\n", cont.ID) return nil }
// eris chains new --options func TestChainsNewConfigOpts(t *testing.T) { // XXX: need to use a different chainID or remove the local tmp/eris/data/chainID dir with each test! chainID := "testChainsNewConfigOpts" do := def.NowDo() do.Name = chainID do.ConfigOpts = []string{"moniker=satoshi", "p2p=1.1.1.1:42", "fast-sync=true"} do.Operations.ContainerNumber = 1 logger.Infof("Creating chain (from tests) =>\t%s\n", do.Name) ifExit(NewChain(do)) // remove the data container defer removeChainContainer(t, chainID, do.Operations.ContainerNumber) // verify the contents of config.toml do.Name = util.DataContainersName(do.Name, do.Operations.ContainerNumber) args := []string{"cat", fmt.Sprintf("/home/eris/.eris/blockchains/%s/config.toml", chainID)} result := string(runContainer(t, do.Name, args)) spl := strings.Split(result, "\n") var found bool for _, s := range spl { if ensureTomlValue(t, s, "moniker", "satoshi") { found = true } if ensureTomlValue(t, s, "node_laddr", "1.1.1.1:42") { found = true } if ensureTomlValue(t, s, "fast_sync", "true") { found = true } } if !found { fatal(t, fmt.Errorf("failed to find fields: %s", result)) } }
//---------------------------------------------------------------------- // validation funcs func checkChainNames(chain *definitions.Chain) { chain.Service.Name = chain.Name chain.Operations.SrvContainerName = util.ChainContainersName(chain.Name, chain.Operations.ContainerNumber) chain.Operations.DataContainerName = util.DataContainersName(chain.Name, chain.Operations.ContainerNumber) }
// MakeChain runs the `eris-cm make` command in a docker container. // It returns an error. Note that if do.Known, do.AccountTypes // or do.ChainType are not set the command will run via interactive // shell. // // do.Name - name of the chain to be created (required) // do.Known - will use the mintgen tool to parse csv's and create a genesis.json (requires do.ChainMakeVals and do.ChainMakeActs) (optional) // do.ChainMakeVals - csv file to use for validators (optional) // do.ChainMakeActs - csv file to use for accounts (optional) // do.AccountTypes - use eris-cm make account-types paradigm (example: Root:1,Participants:25,...) (optional) // do.ChainType - use eris-cm make chain-types paradigm (example: simplechain) (optional) // do.Tarball - instead of outputing raw files in directories, output packages of tarbals (optional) // do.ZipFile - similar to do.Tarball except uses zipfiles (optional) // do.Verbose - verbose output (optional) // do.Debug - debug output (optional) // func MakeChain(do *definitions.Do) error { do.Service.Name = do.Name do.Service.Image = path.Join(version.ERIS_REG_DEF, version.ERIS_IMG_CM) do.Service.User = "******" do.Service.AutoData = true do.Service.Links = []string{fmt.Sprintf("%s:%s", util.ServiceContainersName("keys", do.Operations.ContainerNumber), "keys")} do.Service.Environment = []string{ fmt.Sprintf("ERIS_KEYS_PATH=http://keys:%d", 4767), // note, needs to be made aware of keys port... fmt.Sprintf("ERIS_CHAINMANAGER_ACCOUNTTYPES=%s", strings.Join(do.AccountTypes, ",")), fmt.Sprintf("ERIS_CHAINMANAGER_CHAINTYPE=%s", do.ChainType), fmt.Sprintf("ERIS_CHAINMANAGER_TARBALLS=%v", do.Tarball), fmt.Sprintf("ERIS_CHAINMANAGER_ZIPFILES=%v", do.ZipFile), fmt.Sprintf("ERIS_CHAINMANAGER_OUTPUT=%v", do.Output), fmt.Sprintf("ERIS_CHAINMANAGER_VERBOSE=%v", do.Verbose), fmt.Sprintf("ERIS_CHAINMANAGER_DEBUG=%v", do.Debug), } do.Operations.ContainerType = "service" do.Operations.SrvContainerName = util.ServiceContainersName(do.Name, do.Operations.ContainerNumber) do.Operations.DataContainerName = util.DataContainersName(do.Name, do.Operations.ContainerNumber) if do.RmD { do.Operations.Remove = true } if do.Known { log.Debug("Using MintGen rather than eris:cm") do.Service.EntryPoint = "mintgen" do.Service.Command = fmt.Sprintf("known %s --csv=%s,%s > %s", do.Name, do.ChainMakeVals, do.ChainMakeActs, path.Join(ErisContainerRoot, "chains", do.Name, "genesis.json")) } else { log.Debug("Using eris:cm rather than MintGen") do.Service.EntryPoint = fmt.Sprintf("eris-cm make %s", do.Name) } if !do.Known && len(do.AccountTypes) == 0 && do.ChainType == "" { do.Operations.Interactive = true do.Operations.Args = strings.Split(do.Service.EntryPoint, " ") } if do.Known { do.Operations.Args = append(do.Operations.Args, strings.Split(do.Service.Command, " ")...) do.Service.WorkDir = path.Join(ErisContainerRoot, "chains", do.Name) } doData := definitions.NowDo() doData.Name = do.Name doData.Operations.ContainerNumber = do.Operations.ContainerNumber doData.Operations.DataContainerName = util.DataContainersName(do.Name, do.Operations.ContainerNumber) doData.Operations.ContainerType = "service" if !do.RmD { defer data.RmData(doData) } doData.Source = AccountsTypePath doData.Destination = path.Join(ErisContainerRoot, "chains", "account-types") if err := data.ImportData(doData); err != nil { return err } doData.Source = ChainTypePath doData.Destination = path.Join(ErisContainerRoot, "chains", "chain-types") if err := data.ImportData(doData); err != nil { return err } chnPath := filepath.Join(ChainsPath, do.Name) if _, err := os.Stat(chnPath); !os.IsNotExist(err) { doData.Operations.Args = []string{"mkdir", "--parents", path.Join(ErisContainerRoot, "chains", do.Name)} if err := data.ExecData(doData); err != nil { return err } doData.Operations.Args = []string{} doData.Source = chnPath doData.Destination = path.Join(ErisContainerRoot, "chains", do.Name) if err := data.ImportData(doData); err != nil { return err } } if err := perform.DockerExecService(do.Service, do.Operations); err != nil { return err } doData.Source = path.Join(ErisContainerRoot, "chains") doData.Destination = ErisRoot return data.ExportData(doData) }
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 }
//export from: do.Source(in container), to: do.Destination(on host) func ExportData(do *definitions.Do) error { if util.IsDataContainer(do.Name, do.Operations.ContainerNumber) { log.WithField("=>", do.Name).Info("Exporting data container") // we want to export to a temp directory. exportPath, err := ioutil.TempDir(os.TempDir(), do.Name) // TODO: do.Operations.ContainerNumber ? defer os.Remove(exportPath) if err != nil { return err } containerName := util.DataContainersName(do.Name, do.Operations.ContainerNumber) srv := PretendToBeAService(do.Name, do.Operations.ContainerNumber) service, exists := perform.ContainerExists(srv.Operations) if !exists { return fmt.Errorf("There is no data container for that service.") } reader, writer := io.Pipe() defer reader.Close() if err := checkErisContainerRoot(do, "export"); err != nil { return err } opts := docker.DownloadFromContainerOptions{ OutputStream: writer, Path: do.Source, } go func() { log.WithField("=>", containerName).Info("Copying out of container") log.WithField("path", do.Source).Debug() IfExit(util.DockerClient.DownloadFromContainer(service.ID, opts)) // TODO: be smarter about catching this error writer.Close() }() log.WithField("=>", exportPath).Debug("Untarring package from container") if err = util.Untar(reader, do.Name, exportPath); err != nil { return err } // now if docker dumps to exportPath/.eris we should remove // move everything from .eris to exportPath if err := moveOutOfDirAndRmDir(filepath.Join(exportPath, ".eris"), exportPath); err != nil { return err } // finally remove everything in the data directory and move // the temp contents there if _, err := os.Stat(do.Destination); os.IsNotExist(err) { if e2 := os.MkdirAll(do.Destination, 0755); e2 != nil { return fmt.Errorf("Error:\tThe marmots could neither find, nor had access to make the directory: (%s)\n", do.Destination) } } if err := moveOutOfDirAndRmDir(exportPath, do.Destination); err != nil { return err } } else { return fmt.Errorf("I cannot find that data container. Please check the data container name you sent me.") } do.Result = "success" return nil }
// eris chains new --dir _ -g _ // the default chain_id is my_tests, so should be overwritten func TestChainsNewDirGen(t *testing.T) { chainID := "testChainsNewDirGen" myDir := path.Join(common.DataContainersPath, chainID) if err := os.MkdirAll(myDir, 0700); err != nil { fatal(t, err) } contents := "this is a file in the directory\n" if err := ioutil.WriteFile(path.Join(myDir, "file.file"), []byte(contents), 0600); err != nil { fatal(t, err) } do := def.NowDo() do.GenesisFile = path.Join(common.BlockchainsPath, "default", "genesis.json") do.Name = chainID do.Path = myDir do.Operations.ContainerNumber = 1 logger.Infof("Creating chain (from tests) =>\t%s\n", do.Name) ifExit(NewChain(do)) // remove the data container defer removeChainContainer(t, chainID, do.Operations.ContainerNumber) // verify the contents of file.file - swap config writer with bytes.Buffer // TODO: functions for facilitating this do.Name = util.DataContainersName(do.Name, do.Operations.ContainerNumber) oldWriter := config.GlobalConfig.Writer newWriter := new(bytes.Buffer) config.GlobalConfig.Writer = newWriter args := []string{"cat", fmt.Sprintf("/home/eris/.eris/blockchains/%s/file.file", chainID)} b, err := perform.DockerRunVolumesFromContainer(do.Name, false, args, nil) if err != nil { fatal(t, err) } config.GlobalConfig.Writer = oldWriter result := trimResult(string(b)) contents = trimResult(contents) if result != contents { fatal(t, fmt.Errorf("file not faithfully copied. Got: %s \n Expected: %s", result, contents)) } // verify the chain_id got swapped in the genesis.json // TODO: functions for facilitating this oldWriter = config.GlobalConfig.Writer newWriter = new(bytes.Buffer) config.GlobalConfig.Writer = newWriter args = []string{"cat", fmt.Sprintf("/home/eris/.eris/blockchains/%s/genesis.json", chainID)} //, "|", "jq", ".chain_id"} b, err = perform.DockerRunVolumesFromContainer(do.Name, false, args, nil) if err != nil { fatal(t, err) } config.GlobalConfig.Writer = oldWriter result = string(b) s := struct { ChainID string `json:"chain_id"` }{} if err := json.Unmarshal([]byte(result), &s); err != nil { fatal(t, err) } if s.ChainID != chainID { fatal(t, fmt.Errorf("ChainID mismatch: got %s, expected %s", s.ChainID, chainID)) } }
// the main function for setting up a chain container // handles both "new" and "fetch" - most of the differentiating logic is in the container func setupChain(do *definitions.Do, cmd string) (err error) { // XXX: if do.Name is unique, we can safely assume (and we probably should) that do.Operations.ContainerNumber = 1 // do.Name is mandatory if do.Name == "" { return fmt.Errorf("setupChain requires a chainame") } containerName := util.ChainContainersName(do.Name, do.Operations.ContainerNumber) if do.ChainID == "" { do.ChainID = do.Name } // ensure/create data container if !data.IsKnown(containerName) { if err := perform.DockerCreateDataContainer(do.Name, do.Operations.ContainerNumber); err != nil { return fmt.Errorf("Error creating data containr =>\t%v", err) } } else { logger.Debugln("Data container already exists for", do.Name) } logger.Debugf("Chain's Data Contain Built =>\t%s\n", do.Name) // if something goes wrong, cleanup defer func() { if err != nil { logger.Infof("Error on setupChain =>\t\t%v\n", err) logger.Infoln("Cleaning up...") if err2 := RmChain(do); err2 != nil { // maybe be less dramatic err = fmt.Errorf("Tragic! Our marmots encountered an error during setupChain for %s.\nThey also failed to cleanup after themselves (remove containers) due to another error.\nFirst error =>\t\t\t%v\nCleanup error =>\t\t%v\n", containerName, err, err2) } } }() // copy do.Path, do.GenesisFile, do.ConfigFile, do.Priv, do.CSV into container containerDst := path.Join("blockchains", do.Name) // path in container dst := path.Join(DataContainersPath, do.Name, containerDst) // path on host // TODO: deal with do.Operations.ContainerNumbers ....! // we probably need to update Import logger.Debugln("container destination:", containerDst) logger.Debugln("local destination:", dst) if err = os.MkdirAll(dst, 0700); err != nil { return fmt.Errorf("Error making data directory: %v", err) } var csvFile, csvPath string if do.CSV != "" { csvFile = "genesis.csv" csvPath = fmt.Sprintf("/home/eris/.eris/blockchains/%s/%s", do.ChainID, csvFile) } if err := copyFiles(dst, []stringPair{ {do.Path, ""}, {do.GenesisFile, "genesis.json"}, {do.ConfigFile, "config.toml"}, {do.Priv, "priv_validator.json"}, {do.CSV, csvFile}, }); err != nil { return err } // copy from host to container logger.Debugf("Copying Files into DataCont =>\t%s:%s\n", dst, containerDst) importDo := definitions.NowDo() importDo.Name = do.Name importDo.Operations = do.Operations if err = data.ImportData(importDo); err != nil { return err } chain := loaders.MockChainDefinition(do.Name, do.ChainID, false, do.Operations.ContainerNumber) //set maintainer info chain.Maintainer.Name, chain.Maintainer.Email, err = config.GitConfigUser() if err != nil { logger.Debugf(err.Error()) } // write the chain definition file ... fileName := filepath.Join(BlockchainsPath, do.Name) + ".toml" if _, err = os.Stat(fileName); err != nil { if err = WriteChainDefinitionFile(chain, fileName); err != nil { return fmt.Errorf("error writing chain definition to file: %v", err) } } chain, err = loaders.LoadChainDefinition(do.Name, false, do.Operations.ContainerNumber) if err != nil { return err } logger.Debugf("Chain Loaded. Image =>\t\t%v\n", chain.Service.Image) chain.Operations.PublishAllPorts = do.Operations.PublishAllPorts // TODO: remove this and marshall into struct from cli directly // cmd should be "new" or "install" chain.Service.Command = cmd // do we need to create our own do.GenesisFile? var genGen bool if do.GenesisFile == "" { genGen = true } // write the list of <key>:<value> config options as flags buf := new(bytes.Buffer) for _, cv := range do.ConfigOpts { spl := strings.Split(cv, "=") if len(spl) != 2 { return fmt.Errorf("Config options should be <key>=<value> pairs. Got %s", cv) } buf.WriteString(fmt.Sprintf(" --%s=%s", spl[0], spl[1])) } configOpts := buf.String() // set chainid and other vars envVars := []string{ fmt.Sprintf("CHAIN_ID=%s", do.ChainID), fmt.Sprintf("CONTAINER_NAME=%s", containerName), fmt.Sprintf("RUN=%v", do.Run), fmt.Sprintf("GENERATE_GENESIS=%v", genGen), fmt.Sprintf("CSV=%v", csvPath), fmt.Sprintf("CONFIG_OPTS=%s", configOpts), } logger.Debugf("Set env vars from setupChain =>\t%v\n", envVars) for _, eV := range envVars { chain.Service.Environment = append(chain.Service.Environment, eV) } // TODO: if do.N > 1 ... chain.Operations.DataContainerName = util.DataContainersName(do.Name, do.Operations.ContainerNumber) if os.Getenv("TEST_IN_CIRCLE") != "true" { chain.Operations.Remove = true } logger.Debugf("Starting chain via Docker =>\t%s\n", chain.Service.Name) logger.Debugf("\twith Image =>\t\t%s\n", chain.Service.Image) err = perform.DockerRun(chain.Service, chain.Operations) // this err is caught in the defer above return }
func DefineDappActionService(do *definitions.Do, dapp *definitions.Contracts) error { var cmd string switch do.Name { case "test": cmd = dapp.DappType.TestCmd case "deploy": cmd = dapp.DappType.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 dapp.DappType.Name == "manual" { switch do.Name { case "test": cmd = dapp.TestTask case "deploy": cmd = dapp.DeployTask } } // task flag override if do.Task != "" { dapp.DappType = definitions.GulpDapp() cmd = do.Task } if cmd == "nil" { return fmt.Errorf("I cannot perform that task against that dapp type.\n") } // dapp-specific tests if dapp.DappType.Name == "pyepm" { if do.ConfigFile == "" { return fmt.Errorf("The pyepm dapp type requires a --yaml flag for the package definition you would like to deploy.\n") } else { cmd = do.ConfigFile } } // build service that will run do.Service.Name = dapp.Name + "_tmp_" + do.Name do.Service.Image = dapp.DappType.BaseImage do.Service.AutoData = true do.Service.EntryPoint = dapp.DappType.EntryPoint do.Service.Command = cmd if do.NewName != "" { do.Service.WorkDir = do.NewName // do.NewName is actually where the workdir inside the container goes } 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.Remove = true linkDappToChain(do, dapp) // make data container and import do.Path to do.NewName (if exists) doData := definitions.NowDo() doData.Name = do.Service.Name doData.Operations = do.Operations if do.NewName != "" { doData.Path = do.NewName } loca := path.Join(common.DataContainersPath, doData.Name) logger.Debugf("Creating Dapp Data Cont =>\t%s:%s\n", do.Path, loca) common.Copy(do.Path, loca) data.ImportData(doData) do.Operations.DataContainerName = util.DataContainersName(doData.Name, doData.Operations.ContainerNumber) logger.Debugf("DApp Action Built.\n") return nil }
// the main function for setting up a chain container // handles both "new" and "fetch" - most of the differentiating logic is in the container func setupChain(do *definitions.Do, cmd string) (err error) { // XXX: if do.Name is unique, we can safely assume (and we probably should) that do.Operations.ContainerNumber = 1 // do.Name is mandatory if do.Name == "" { return fmt.Errorf("setupChain requires a chainame") } containerName := util.ChainContainersName(do.Name, do.Operations.ContainerNumber) if do.ChainID == "" { do.ChainID = do.Name } //if given path does not exist, see if its a reference to something in ~/.eris/chains/chainName if do.Path != "" { src, err := os.Stat(do.Path) if err != nil || !src.IsDir() { logger.Infof("Path (%s) does not exist or is not a directory, trying $HOME/.eris/chains/%s\n", do.Path, do.Path) do.Path, err = util.ChainsPathChecker(do.Path) if err != nil { return err } } } else if do.GenesisFile == "" && do.CSV == "" && len(do.ConfigOpts) == 0 { // NOTE: this expects you to have ~/.eris/chains/default/ (ie. to have run `eris init`) do.Path, err = util.ChainsPathChecker("default") if err != nil { return err } } // ensure/create data container if !data.IsKnown(do.Name) { ops := loaders.LoadDataDefinition(do.Name, do.Operations.ContainerNumber) if err := perform.DockerCreateData(ops); err != nil { return fmt.Errorf("Error creating data container =>\t%v", err) } } else { logger.Debugln("Data container already exists for", do.Name) } logger.Debugf("Chain's Data Contain Built =>\t%s\n", do.Name) // if something goes wrong, cleanup defer func() { if err != nil { logger.Infof("Error on setupChain =>\t\t%v\n", err) logger.Infoln("Cleaning up...") if err2 := RmChain(do); err2 != nil { // maybe be less dramatic err = fmt.Errorf("Tragic! Our marmots encountered an error during setupChain for %s.\nThey also failed to cleanup after themselves (remove containers) due to another error.\nFirst error =>\t\t\t%v\nCleanup error =>\t\t%v\n", containerName, err, err2) } } }() // copy do.Path, do.GenesisFile, do.ConfigFile, do.Priv, do.CSV into container containerDst := path.Join("chains", do.Name) // path in container dst := path.Join(DataContainersPath, do.Name, containerDst) // path on host // TODO: deal with do.Operations.ContainerNumbers ....! // we probably need to update Import logger.Debugf("Container destination =>\t%s\n", containerDst) logger.Debugf("Local destination =>\t\t%s\n", dst) if err = os.MkdirAll(dst, 0700); err != nil { return fmt.Errorf("Error making data directory: %v", err) } // we accept two csvs: one for validators, one for accounts // if there's only one, its for validators and accounts var csvFiles []string var csvPaths string if do.CSV != "" { csvFiles = strings.Split(do.CSV, ",") if len(csvFiles) > 1 { csvPath1 := fmt.Sprintf("%s/%s/%s/%s", ErisContainerRoot, "chains", do.ChainID, "validators.csv") csvPath2 := fmt.Sprintf("%s/%s/%s/%s", ErisContainerRoot, "chains", do.ChainID, "accounts.csv") csvPaths = fmt.Sprintf("%s,%s", csvPath1, csvPath2) } else { csvPaths = fmt.Sprintf("%s/%s/%s/%s", ErisContainerRoot, "chains", do.ChainID, "genesis.csv") } } filesToCopy := []stringPair{ {do.Path, ""}, {do.GenesisFile, "genesis.json"}, {do.ConfigFile, "config.toml"}, {do.Priv, "priv_validator.json"}, } if len(csvFiles) == 1 { filesToCopy = append(filesToCopy, stringPair{csvFiles[0], "genesis.csv"}) } else if len(csvFiles) > 1 { filesToCopy = append(filesToCopy, stringPair{csvFiles[0], "validators.csv"}) filesToCopy = append(filesToCopy, stringPair{csvFiles[1], "accounts.csv"}) } logger.Infof("Copying chain files into the correct location.\n") if err := copyFiles(dst, filesToCopy); err != nil { return err } // copy from host to container logger.Debugf("Copying Files into DataCont =>\t%s:%s\n", dst, containerDst) importDo := definitions.NowDo() importDo.Name = do.Name importDo.Operations = do.Operations importDo.Destination = ErisContainerRoot importDo.Source = filepath.Join(DataContainersPath, do.Name) if err = data.ImportData(importDo); err != nil { return err } chain := loaders.MockChainDefinition(do.Name, do.ChainID, false, do.Operations.ContainerNumber) //set maintainer info chain.Maintainer.Name, chain.Maintainer.Email, err = config.GitConfigUser() if err != nil { logger.Debugf(err.Error()) } // write the chain definition file ... fileName := filepath.Join(ChainsPath, do.Name) + ".toml" if _, err = os.Stat(fileName); err != nil { if err = WriteChainDefinitionFile(chain, fileName); err != nil { return fmt.Errorf("error writing chain definition to file: %v", err) } } chain, err = loaders.LoadChainDefinition(do.Name, false, do.Operations.ContainerNumber) if err != nil { return err } logger.Debugf("Chain Loaded. Image =>\t\t%v\n", chain.Service.Image) chain.Operations.PublishAllPorts = do.Operations.PublishAllPorts // TODO: remove this and marshall into struct from cli directly // cmd should be "new" or "install" chain.Service.Command = cmd // write the list of <key>:<value> config options as flags buf := new(bytes.Buffer) for _, cv := range do.ConfigOpts { spl := strings.Split(cv, "=") if len(spl) != 2 { return fmt.Errorf("Config options should be <key>=<value> pairs. Got %s", cv) } buf.WriteString(fmt.Sprintf(" --%s=%s", spl[0], spl[1])) } configOpts := buf.String() // set chainid and other vars envVars := []string{ fmt.Sprintf("CHAIN_ID=%s", do.ChainID), fmt.Sprintf("CONTAINER_NAME=%s", containerName), fmt.Sprintf("CSV=%v", csvPaths), // for mintgen fmt.Sprintf("CONFIG_OPTS=%s", configOpts), // for config.toml fmt.Sprintf("NODE_ADDR=%s", do.Gateway), // etcb host fmt.Sprintf("DOCKER_FIX=%s", " "), // https://github.com/docker/docker/issues/14203 } envVars = append(envVars, do.Env...) if do.Run { // run erisdb instead of tendermint envVars = append(envVars, "ERISDB_API=true") } logger.Debugf("Set env vars from setupChain =>\t%v\n", envVars) chain.Service.Environment = append(chain.Service.Environment, envVars...) logger.Debugf("Set links from setupChain =>\t%v\n", do.Links) chain.Service.Links = append(chain.Service.Links, do.Links...) // TODO: if do.N > 1 ... chain.Operations.DataContainerName = util.DataContainersName(do.Name, do.Operations.ContainerNumber) if err := bootDependencies(chain, do); err != nil { return err } logger.Debugf("Starting chain via Docker =>\t%s\n", chain.Service.Name) logger.Debugf("\twith Image =>\t\t%s\n", chain.Service.Image) err = perform.DockerRunService(chain.Service, chain.Operations) // this err is caught in the defer above return }
// the main function for setting up a chain container // handles both "new" and "fetch" - most of the differentiating logic is in the container func setupChain(do *definitions.Do, cmd string) (err error) { // XXX: if do.Name is unique, we can safely assume (and we probably should) that do.Operations.ContainerNumber = 1 // do.Name is mandatory if do.Name == "" { return fmt.Errorf("setupChain requires a chainame") } containerName := util.ChainContainersName(do.Name, do.Operations.ContainerNumber) if do.ChainID == "" { do.ChainID = do.Name } // do.Run containers and exit (creates data container) if !data.IsKnown(containerName) { if err := perform.DockerCreateDataContainer(do.Name, do.Operations.ContainerNumber); err != nil { return fmt.Errorf("Error creating data containr =>\t%v", err) } } logger.Debugf("Chain's Data Contain Built =>\t%s\n", do.Name) // if something goes wrong, cleanup defer func() { if err != nil { logger.Infof("Error on setupChain =>\t\t%v\n", err) logger.Infoln("Cleaning up...") if err2 := RmChain(do); err2 != nil { err = fmt.Errorf("Tragic! Our marmots encountered an error during setupChain for %s.\nThey also failed to cleanup after themselves (remove containers) due to another error.\nFirst error =>\t\t\t%v\nCleanup error =>\t\t%v\n", containerName, err, err2) } } }() // copy do.Path, do.GenesisFile, config into container containerDst := path.Join("blockchains", do.Name) // path in container dst := path.Join(DataContainersPath, do.Name, containerDst) // path on host // TODO: deal with do.Operations.ContainerNumbers ....! // we probably need to update Import if err = os.MkdirAll(dst, 0700); err != nil { return fmt.Errorf("Error making data directory: %v", err) } if do.Path != "" { if err = Copy(do.Path, dst); err != nil { return err } } if do.GenesisFile != "" { if err = Copy(do.GenesisFile, path.Join(dst, "genesis.json")); err != nil { return err } } else { // TODO: do.Run mintgen and open the do.GenesisFile in editor } if do.ConfigFile != "" { if err = Copy(do.ConfigFile, path.Join(dst, "config."+path.Ext(do.ConfigFile))); err != nil { return err } } // copy from host to container logger.Debugf("Copying Files into DataCont =>\t%s:%s\n", dst, containerDst) importDo := definitions.NowDo() importDo.Name = do.Name importDo.Operations = do.Operations if err = data.ImportData(importDo); err != nil { return err } chain := loaders.MockChainDefinition(do.Name, do.ChainID, false, do.Operations.ContainerNumber) //get maintainer info uName, err := gitconfig.Username() if err != nil { logger.Debugf("Could not find git user.name, setting chain.Maintainer.Name = \"\"") uName = "" } email, err := gitconfig.Email() if err != nil { logger.Debugf("Could not find git user.email, setting chain.Maintainer.Email = \"\"") email = "" } chain.Maintainer.Name = uName chain.Maintainer.Email = email // write the chain definition file ... fileName := filepath.Join(BlockchainsPath, do.Name) + ".toml" if _, err = os.Stat(fileName); err != nil { if err = WriteChainDefinitionFile(chain, fileName); err != nil { return fmt.Errorf("error writing chain definition to file: %v", err) } } chain, err = loaders.LoadChainDefinition(do.Name, false, do.Operations.ContainerNumber) if err != nil { return err } logger.Debugf("Chain Loaded. Image =>\t\t%v\n", chain.Service.Image) chain.Operations.PublishAllPorts = do.Operations.PublishAllPorts // TODO: remove this and marshall into struct from cli directly // cmd should be "new" or "install" chain.Service.Command = cmd // do we need to create our own do.GenesisFile? var genGen bool if do.GenesisFile == "" { genGen = true } // set chainid and other vars envVars := []string{ "CHAIN_ID=" + do.ChainID, "CONTAINER_NAME=" + containerName, fmt.Sprintf("RUN=%v", do.Run), fmt.Sprintf("GENERATE_GENESIS=%v", genGen), } logger.Debugf("Set env vars from setupChain =>\t%v\n", envVars) for _, eV := range envVars { chain.Service.Environment = append(chain.Service.Environment, eV) } // TODO mint vs. erisdb (in terms of rpc) chain.Operations.DataContainerName = util.DataContainersName(do.Name, do.Operations.ContainerNumber) if os.Getenv("TEST_IN_CIRCLE") != "true" { chain.Operations.Remove = true } logger.Debugf("Starting chain via Docker =>\t%s\n", chain.Service.Name) logger.Debugf("\twith Image =>\t\t%s\n", chain.Service.Image) err = perform.DockerRun(chain.Service, chain.Operations) // this err is caught in the defer above return }
//return to handle failings in each pkg //typ = type of test for dealing with do.() details func TestExistAndRun(name, typ string, contNum int, toExist, toRun bool) bool { var exist, run bool if typ == "actions" { name = strings.Replace(name, " ", "_", -1) // dirty } //logger.Infof("\nTesting whether (%s) existing? (%t)\n", name, toExist) logger.Infof("\nTesting whether (%s) is running? (%t) and existing? (%t)\n", name, toRun, toExist) if typ == "chains" { name = util.ChainContainersName(name, 1) // not worried about containerNumbers, deal with multiple containers in services tests } else if typ == "services" { name = util.ServiceContainersName(name, contNum) } else { name = util.DataContainersName(name, 1) } do := def.NowDo() do.Quiet = true do.Operations.Args = []string{"testing"} if typ == "data" || typ == "chains" || typ == "services" { do.Existing = true } else if typ == "actions" { do.Known = true } if err := util.ListAll(do, typ); err != nil { logger.Errorln(err) return true } res := strings.Split(do.Result, "\n") for _, r := range res { logger.Debugf("Existing =>\t\t\t%s\n", r) if r == util.ContainersShortName(name) { exist = true } } if toExist != exist { if toExist { logger.Infof("Could not find an existing =>\t%s\n", name) } else { logger.Infof("Found an existing instance of %s when I shouldn't have\n", name) } return true } //func should always be testing for toExist, only sometimes tested for runining if typ == "chains" || typ == "services" { do.Running = true do.Existing = false //unset if err := util.ListAll(do, typ); err != nil { return true } logger.Debugln("RUNNING RESULT:", do.Result) res = strings.Split(do.Result, "\n") for _, r := range res { logger.Debugf("Running =>\t\t\t%s\n", r) if r == util.ContainersShortName(name) { run = true } } if toRun != run { if toRun { logger.Infof("Could not find a running =>\t%s\n", name) } else { logger.Infof("Found a running instance of %s when I shouldn't have\n", name) } return true } } return false }