func (a *autoScaleConfig) removeNode(chosenNode *cluster.Node) error { _, hasIaas := chosenNode.Metadata["iaas"] if !hasIaas { return fmt.Errorf("no IaaS information in node (%s) metadata: %#v", chosenNode.Address, chosenNode.Metadata) } err := a.provisioner.getCluster().Unregister(chosenNode.Address) if err != nil { return fmt.Errorf("unable to unregister node (%s) for removal: %s", chosenNode.Address, err) } buf := safe.NewBuffer(nil) err = a.provisioner.moveContainers(urlToHost(chosenNode.Address), "", buf) if err != nil { a.provisioner.getCluster().Register(chosenNode.Address, chosenNode.Metadata) return fmt.Errorf("unable to move containers from node (%s): %s - log: %s", chosenNode.Address, err, buf.String()) } m, err := iaas.FindMachineByIdOrAddress(chosenNode.Metadata["iaas-id"], urlToHost(chosenNode.Address)) if err != nil { a.logError("unable to find machine for removal in iaas: %s", err) return nil } err = m.Destroy() if err != nil { a.logError("unable to destroy machine in IaaS: %s", err) } return nil }
func (s *S) TestAppShellSpecifyUnit(c *check.C) { a := app.App{ Name: "someapp", Platform: "zend", Teams: []string{s.team.Name}, } err := s.conn.Apps().Insert(a) c.Assert(err, check.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) defer s.logConn.Logs(a.Name).DropCollection() err = s.provisioner.Provision(&a) c.Assert(err, check.IsNil) defer s.provisioner.Destroy(&a) s.provisioner.AddUnits(&a, 5, "web", nil) unit := s.provisioner.Units(&a)[3] url := fmt.Sprintf("/shell?:app=%s&width=140&height=38&term=xterm&unit=%s", a.Name, unit.Name) request, err := http.NewRequest("GET", url, nil) c.Assert(err, check.IsNil) buf := safe.NewBuffer([]byte("echo teste")) recorder := provisiontest.Hijacker{Conn: &provisiontest.FakeConn{Buf: buf}} err = remoteShellHandler(&recorder, request, s.token) c.Assert(err, check.IsNil) shells := s.provisioner.Shells(unit.Name) c.Assert(shells, check.HasLen, 1) c.Assert(shells[0].App.GetName(), check.Equals, a.Name) c.Assert(shells[0].Width, check.Equals, 140) c.Assert(shells[0].Height, check.Equals, 38) c.Assert(shells[0].Term, check.Equals, "xterm") c.Assert(shells[0].Unit, check.Equals, unit.Name) for _, u := range s.provisioner.Units(&a) { if u.Name != unit.Name { c.Check(s.provisioner.Shells(u.Name), check.HasLen, 0) } } }
func (s *S) TestEnsureContainersStartedOnlyChild(c *check.C) { err := nodecontainer.AddNewContainer("p1", &nodecontainer.NodeContainerConfig{ Name: "c1", Config: docker.Config{ Image: "myregistry/tsuru/bs", }, }) c.Assert(err, check.IsNil) p, err := dockertest.StartMultipleServersCluster() c.Assert(err, check.IsNil) defer p.Destroy() clust := p.Cluster() nodes, err := clust.Nodes() c.Assert(err, check.IsNil) c.Assert(nodes, check.HasLen, 2) nodes[0].Metadata["pool"] = "p1" _, err = p.Cluster().UpdateNode(nodes[0]) c.Assert(err, check.IsNil) nodes[1].Metadata["pool"] = "p2" _, err = p.Cluster().UpdateNode(nodes[1]) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) client, err := docker.NewClient(nodes[0].Address) c.Assert(err, check.IsNil) containers, err := client.ListContainers(docker.ListContainersOptions{All: true}) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) client2, err := docker.NewClient(nodes[1].Address) c.Assert(err, check.IsNil) containers2, err := client2.ListContainers(docker.ListContainersOptions{All: true}) c.Assert(err, check.IsNil) c.Assert(containers2, check.HasLen, 0) }
func (s *HandlersSuite) TestSSHToContainerHandler(c *gocheck.C) { sshServer := newMockSSHServer(c, 2e9) defer sshServer.Shutdown() coll := collection() defer coll.Close() container := container{ ID: "9930c24f1c4x", AppName: "makea", Type: "python", Status: provision.StatusStarted.String(), IP: "127.0.0.4", HostPort: "9025", HostAddr: "localhost", SSHHostPort: sshServer.port, PrivateKey: string(fakeServerPrivateKey), User: sshUsername(), } err := coll.Insert(container) c.Assert(err, gocheck.IsNil) defer coll.RemoveAll(bson.M{"appname": "makea"}) tmpDir, err := ioutil.TempDir("", "containerssh") defer os.RemoveAll(tmpDir) filepath := path.Join(tmpDir, "file.txt") file, err := os.Create(filepath) c.Assert(err, gocheck.IsNil) file.Write([]byte("hello")) file.Close() buf := safe.NewBuffer([]byte("cat " + filepath + "\nexit\n")) recorder := hijacker{conn: &fakeConn{buf}} request, err := http.NewRequest("GET", "/?:container_id="+container.ID, nil) c.Assert(err, gocheck.IsNil) err = sshToContainerHandler(&recorder, request, nil) c.Assert(err, gocheck.IsNil) }
func (s *S) SetUpTest(c *check.C) { config.Set("docker:api-timeout", 2) iaas.ResetAll() repositorytest.Reset() queue.ResetQueue() repository.Manager().CreateUser(s.user.Email) s.p = &dockerProvisioner{storage: &cluster.MapStorage{}} err := s.p.Initialize() c.Assert(err, check.IsNil) queue.ResetQueue() s.server, err = dtesting.NewServer("127.0.0.1:0", nil, nil) c.Assert(err, check.IsNil) s.p.cluster, err = cluster.New(nil, s.p.storage, cluster.Node{Address: s.server.URL(), Metadata: map[string]string{"pool": "test-default"}}, ) c.Assert(err, check.IsNil) mainDockerProvisioner = s.p err = dbtest.ClearAllCollectionsExcept(s.storage.Apps().Database, []string{"users", "tokens", "teams"}) c.Assert(err, check.IsNil) err = clearClusterStorage(s.clusterSess) c.Assert(err, check.IsNil) routertest.FakeRouter.Reset() opts := provision.AddPoolOptions{Name: "test-default", Default: true} err = provision.AddPool(opts) c.Assert(err, check.IsNil) s.storage.Tokens().Remove(bson.M{"appname": bson.M{"$ne": ""}}) s.logBuf = safe.NewBuffer(nil) log.SetLogger(log.NewWriterLogger(s.logBuf, true)) s.token = createTokenForUser(s.user, "*", string(permission.CtxGlobal), "", c) }
func (s *S) TestFollowLogsAndCommitForward(c *check.C) { err := s.newFakeImage(s.p, "tsuru/python", nil) c.Assert(err, check.IsNil) app := provisiontest.NewFakeApp("mightyapp", "python", 1) nextImgName, err := appNewImageName(app.GetName()) c.Assert(err, check.IsNil) cont := container.Container{AppName: "mightyapp", ID: "myid123", BuildingImage: nextImgName} err = cont.Create(&container.CreateArgs{ App: app, ImageID: "tsuru/python", Commands: []string{"foo"}, Provisioner: s.p, }) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) args := runContainerActionsArgs{writer: buf, provisioner: s.p} context := action.FWContext{Params: []interface{}{args}, Previous: cont} imageId, err := followLogsAndCommit.Forward(context) c.Assert(err, check.IsNil) c.Assert(imageId, check.Equals, "tsuru/app-mightyapp:v1") c.Assert(buf.String(), check.Not(check.Equals), "") var dbCont container.Container coll := s.p.Collection() defer coll.Close() err = coll.Find(bson.M{"id": cont.ID}).One(&dbCont) c.Assert(err, check.NotNil) c.Assert(err.Error(), check.Equals, "not found") _, err = s.p.Cluster().InspectContainer(cont.ID) c.Assert(err, check.NotNil) c.Assert(err.Error(), check.Matches, "No such container.*") err = s.p.Cluster().RemoveImage("tsuru/app-mightyapp:v1") c.Assert(err, check.IsNil) }
func (s *S) TestBindAndHealthcheckBackward(c *check.C) { appName := "my-fake-app" err := s.newFakeImage(s.p, "tsuru/app-"+appName, nil) c.Assert(err, check.IsNil) fakeApp := provisiontest.NewFakeApp(appName, "python", 0) s.p.Provision(fakeApp) defer s.p.Destroy(fakeApp) buf := safe.NewBuffer(nil) args := changeUnitsPipelineArgs{ app: fakeApp, provisioner: s.p, writer: buf, toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, imageId: "tsuru/app-" + appName, } containers, err := addContainersWithHost(&args) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 2) context := action.BWContext{Params: []interface{}{args}, FWResult: containers} for _, c := range containers { u := c.AsUnit(fakeApp) fakeApp.BindUnit(&u) } bindAndHealthcheck.Backward(context) c.Assert(err, check.IsNil) u1 := containers[0].AsUnit(fakeApp) c.Assert(fakeApp.HasBind(&u1), check.Equals, false) u2 := containers[1].AsUnit(fakeApp) c.Assert(fakeApp.HasBind(&u2), check.Equals, false) }
func (s *S) TestMoveContainerErrorStarted(c *check.C) { p, err := s.startMultipleServersCluster() c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) p.Provision(appInstance) imageId, err := image.AppCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) addedConts, err := addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, app: appInstance, imageId: imageId, provisioner: p, }) c.Assert(err, check.IsNil) err = addedConts[0].SetStatus(p, provision.StatusError, true) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) _, err = p.moveContainer(addedConts[0].ID[:6], "127.0.0.1", buf) c.Assert(err, check.IsNil) containers, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) containers, err = p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) c.Assert(containers[0].Status, check.Equals, provision.StatusStarting.String()) }
func (s *S) TestFollowLogsAndCommitForwardWaitFailure(c *check.C) { s.server.PrepareFailure("failed to wait for the container", "/containers/.*/wait") defer s.server.ResetFailure("failed to wait for the container") err := s.newFakeImage(s.p, "tsuru/python", nil) c.Assert(err, check.IsNil) app := provisiontest.NewFakeApp("myapp", "python", 1) cont := container.Container{AppName: "mightyapp"} err = cont.Create(&container.CreateArgs{ App: app, ImageID: "tsuru/python", Commands: []string{"foo"}, Provisioner: s.p, }) c.Assert(err, check.IsNil) err = cont.Start(&container.StartArgs{ Provisioner: s.p, App: app, }) c.Assert(err, check.IsNil) err = cont.Stop(s.p) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) args := runContainerActionsArgs{writer: buf, provisioner: s.p} context := action.FWContext{Params: []interface{}{args}, Previous: cont} imageId, err := followLogsAndCommit.Forward(context) c.Assert(err, check.ErrorMatches, `.*failed to wait for the container\n$`) c.Assert(imageId, check.IsNil) }
func (s *S) TestRebalanceContainers(c *check.C) { p, err := s.startMultipleServersCluster() c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) defer p.Destroy(appInstance) p.Provision(appInstance) imageId, err := appCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) _, err = addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 5}}, app: appInstance, imageId: imageId, provisioner: p, }) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = p.rebalanceContainers(buf, false) c.Assert(err, check.IsNil) c1, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c2, err := p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert((len(c1) == 3 && len(c2) == 2) || (len(c1) == 2 && len(c2) == 3), check.Equals, true) }
func (s *S) TestEnsureContainersStartedForceStopOnlyOnFailure(c *check.C) { config.Set("docker:bs:image", "myregistry/tsuru/bs") _, err := nodecontainer.InitializeBS() c.Assert(err, check.IsNil) var reqs []*http.Request server, err := testing.NewServer("127.0.0.1:0", nil, func(r *http.Request) { reqs = append(reqs, r) }) c.Assert(err, check.IsNil) defer server.Stop() errCount := 0 server.CustomHandler("/containers/big-sibling", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { reqs = append(reqs, r) if r.Method != "DELETE" { server.DefaultHandler().ServeHTTP(w, r) return } errCount++ if errCount > 2 { server.DefaultHandler().ServeHTTP(w, r) } else { w.WriteHeader(http.StatusInternalServerError) } })) p, err := dockertest.NewFakeDockerProvisioner(server.URL()) c.Assert(err, check.IsNil) defer p.Destroy() client, err := docker.NewClient(server.URL()) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) reqs = nil err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) var paths []string for _, r := range reqs { paths = append(paths, r.Method+" "+r.URL.Path) } c.Assert(paths, check.DeepEquals, []string{ "POST /images/create", "POST /containers/create", "POST /containers/big-sibling/stop", "DELETE /containers/big-sibling", "DELETE /containers/big-sibling", "DELETE /containers/big-sibling", "POST /containers/create", "GET /version", "POST /containers/big-sibling/start", }) c.Assert(reqs[3].URL.Query().Get("force"), check.Equals, "") c.Assert(reqs[4].URL.Query().Get("force"), check.Equals, "1") c.Assert(reqs[5].URL.Query().Get("force"), check.Equals, "1") containers, err := client.ListContainers(docker.ListContainersOptions{All: true}) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) container, err := client.InspectContainer(containers[0].ID) c.Assert(err, check.IsNil) c.Assert(container.Name, check.Equals, nodecontainer.BsDefaultName) }
func (s *S) TestRebalanceContainersManyApps(c *check.C) { p, err := s.startMultipleServersCluster() c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-otherapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) defer p.Destroy(appInstance) p.Provision(appInstance) appInstance2 := provisiontest.NewFakeApp("otherapp", "python", 0) defer p.Destroy(appInstance2) p.Provision(appInstance2) imageId, err := image.AppCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) _, err = addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 1}}, app: appInstance, imageId: imageId, provisioner: p, }) c.Assert(err, check.IsNil) imageId2, err := image.AppCurrentImageName(appInstance2.GetName()) c.Assert(err, check.IsNil) _, err = addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 1}}, app: appInstance2, imageId: imageId2, provisioner: p, }) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), Pool: "test-default", } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) appStruct2 := &app.App{ Name: appInstance2.GetName(), Pool: "test-default", } err = s.storage.Apps().Insert(appStruct2) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) c1, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c.Assert(c1, check.HasLen, 2) err = p.rebalanceContainers(buf, false) c.Assert(err, check.IsNil) c1, err = p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c.Assert(c1, check.HasLen, 1) c2, err := p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(c2, check.HasLen, 1) }
func (s *S) TestBindAndHealthcheckDontHealtcheckForErroredApps(c *check.C) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) })) defer server.Close() conn, err := db.Conn() c.Assert(err, check.IsNil) defer conn.Close() dbApp := &app.App{Name: "myapp"} err = conn.Apps().Insert(dbApp) c.Assert(err, check.IsNil) defer conn.Apps().Remove(bson.M{"name": dbApp.Name}) imageName := "tsuru/app-" + dbApp.Name customData := map[string]interface{}{ "healthcheck": map[string]interface{}{ "path": "/x/y", "status": http.StatusOK, }, "procfile": "web: python myapp.py", } err = s.newFakeImage(s.p, imageName, customData) c.Assert(err, check.IsNil) fakeApp := provisiontest.NewFakeApp(dbApp.Name, "python", 0) s.p.Provision(fakeApp) defer s.p.Destroy(fakeApp) buf := safe.NewBuffer(nil) contOpts := newContainerOpts{ Status: "error", } oldContainer, err := s.newContainer(&contOpts, nil) c.Assert(err, check.IsNil) args := changeUnitsPipelineArgs{ app: fakeApp, provisioner: s.p, writer: buf, toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, imageId: "tsuru/app-" + dbApp.Name, toRemove: []container{*oldContainer}, } containers, err := addContainersWithHost(&args) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 2) url, _ := url.Parse(server.URL) host, port, _ := net.SplitHostPort(url.Host) containers[0].HostAddr = host containers[0].HostPort = port containers[1].HostAddr = host containers[1].HostPort = port context := action.FWContext{Params: []interface{}{args}, Previous: containers} result, err := bindAndHealthcheck.Forward(context) c.Assert(err, check.IsNil) resultContainers := result.([]container) c.Assert(resultContainers, check.DeepEquals, containers) u1 := containers[0].asUnit(fakeApp) u2 := containers[1].asUnit(fakeApp) c.Assert(fakeApp.HasBind(&u1), check.Equals, true) c.Assert(fakeApp.HasBind(&u2), check.Equals, true) }
func (s *S) TestRebalanceContainersByHost(c *check.C) { otherServer, err := dtesting.NewServer("localhost:0", nil, nil) c.Assert(err, check.IsNil) defer otherServer.Stop() otherUrl := strings.Replace(otherServer.URL(), "127.0.0.1", "localhost", 1) p := &dockerProvisioner{} err = p.Initialize() c.Assert(err, check.IsNil) p.storage = &cluster.MapStorage{} p.scheduler = &segregatedScheduler{provisioner: p} p.cluster, err = cluster.New(p.scheduler, p.storage, cluster.Node{Address: s.server.URL(), Metadata: map[string]string{"pool": "pool1"}}, cluster.Node{Address: otherUrl, Metadata: map[string]string{"pool": "pool1"}}, ) c.Assert(err, check.IsNil) opts := provision.AddPoolOptions{Name: "pool1"} err = provision.AddPool(opts) c.Assert(err, check.IsNil) err = provision.AddTeamsToPool("pool1", []string{"team1"}) c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) defer p.Destroy(appInstance) p.Provision(appInstance) imageId, err := appCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) _, err = addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 5}}, app: appInstance, imageId: imageId, provisioner: p, }) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), TeamOwner: "team1", Pool: "pool1", } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) c1, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c.Assert(c1, check.HasLen, 5) c2, err := p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(c2, check.HasLen, 0) err = p.Cluster().Unregister(otherUrl) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = p.rebalanceContainersByHost(net.URLToHost(otherUrl), buf) c.Assert(err, check.IsNil) c.Assert(p.scheduler.ignoredContainers, check.IsNil) c2, err = p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(c2, check.HasLen, 5) }
func (a *autoScaleConfig) rebalanceIfNeeded(event *autoScaleEvent, groupMetadata string, nodes []*cluster.Node) error { if a.preventRebalance { return nil } var rebalanceFilter map[string]string if a.groupByMetadata != "" { rebalanceFilter = map[string]string{a.groupByMetadata: groupMetadata} } if event.Action == "" { // No action yet, check if we need rebalance _, gap, err := a.provisioner.containerGapInNodes(nodes) buf := safe.NewBuffer(nil) dryProvisioner, err := a.provisioner.rebalanceContainersByFilter(buf, nil, rebalanceFilter, true) if err != nil { return fmt.Errorf("unable to run dry rebalance to check if rebalance is needed: %s - log: %s", err, buf.String()) } if dryProvisioner == nil { return nil } _, gapAfter, err := dryProvisioner.containerGapInNodes(nodes) if err != nil { return fmt.Errorf("couldn't find containers from rebalanced nodes: %s", err) } if math.Abs((float64)(gap-gapAfter)) > 2.0 { err = event.update(scaleActionRebalance, fmt.Sprintf("gap is %d, after rebalance gap will be %d", gap, gapAfter)) if err != nil { return fmt.Errorf("unable to update event: %s", err) } } } if event.Action != "" && event.Action != scaleActionRemove { a.logDebug("running rebalance, due to %q for %q: %s", event.Action, event.MetadataValue, event.Reason) buf := safe.NewBuffer(nil) var writer io.Writer = buf if a.writer != nil { writer = io.MultiWriter(buf, a.writer) } _, err := a.provisioner.rebalanceContainersByFilter(writer, nil, rebalanceFilter, false) if err != nil { return fmt.Errorf("unable to rebalance containers: %s - log: %s", err.Error(), buf.String()) } return nil } return nil }
func (s *S) TestRebalanceContainersDry(c *check.C) { p, err := s.startMultipleServersCluster() c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) defer p.Destroy(appInstance) p.Provision(appInstance) imageId, err := image.AppCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) args := changeUnitsPipelineArgs{ app: appInstance, toAdd: map[string]*containersToAdd{"web": {Quantity: 5}}, imageId: imageId, provisioner: p, toHost: "localhost", } pipeline := action.NewPipeline( &provisionAddUnitsToHost, &bindAndHealthcheck, &addNewRoutes, &setRouterHealthcheck, &updateAppImage, ) err = pipeline.Execute(args) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), Pool: "test-default", } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) router, err := getRouterForApp(appInstance) c.Assert(err, check.IsNil) beforeRoutes, err := router.Routes(appStruct.Name) c.Assert(err, check.IsNil) c.Assert(beforeRoutes, check.HasLen, 5) var serviceCalled bool rollback := s.addServiceInstance(c, appInstance.GetName(), nil, func(w http.ResponseWriter, r *http.Request) { serviceCalled = true w.WriteHeader(http.StatusOK) }) defer rollback() buf := safe.NewBuffer(nil) err = p.rebalanceContainers(buf, true) c.Assert(err, check.IsNil) c1, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c2, err := p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(c1, check.HasLen, 5) c.Assert(c2, check.HasLen, 0) routes, err := router.Routes(appStruct.Name) c.Assert(err, check.IsNil) c.Assert(routes, check.DeepEquals, beforeRoutes) c.Assert(serviceCalled, check.Equals, false) }
func (s *S) TestMoveContainer(c *check.C) { p, err := s.startMultipleServersCluster() c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) defer p.Destroy(appInstance) p.Provision(appInstance) coll := p.Collection() defer coll.Close() coll.Insert(container.Container{ ID: "container-id", AppName: appInstance.GetName(), Version: "container-version", Image: "tsuru/python", }) defer coll.RemoveAll(bson.M{"appname": appInstance.GetName()}) imageId, err := image.AppCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) addedConts, err := addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, app: appInstance, imageId: imageId, provisioner: p, }) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) var serviceBodies []string var serviceMethods []string rollback := s.addServiceInstance(c, appInstance.GetName(), []string{addedConts[0].ID}, func(w http.ResponseWriter, r *http.Request) { data, _ := ioutil.ReadAll(r.Body) serviceBodies = append(serviceBodies, string(data)) serviceMethods = append(serviceMethods, r.Method) w.WriteHeader(http.StatusOK) }) defer rollback() _, err = p.moveContainer(addedConts[0].ID[:6], "127.0.0.1", buf) c.Assert(err, check.IsNil) containers, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) containers, err = p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) c.Assert(serviceBodies, check.HasLen, 2) c.Assert(serviceMethods, check.HasLen, 2) c.Assert(serviceMethods[0], check.Equals, "POST") c.Assert(serviceBodies[0], check.Matches, ".*unit-host=127.0.0.1") c.Assert(serviceMethods[1], check.Equals, "DELETE") c.Assert(serviceBodies[1], check.Matches, ".*unit-host=localhost") }
func (a *autoScaleConfig) rebalanceIfNeeded(evt *event.Event, pool string, nodes []*cluster.Node, sResult *scalerResult) error { if len(sResult.ToRemove) > 0 { return nil } if sResult.ToAdd > 0 { sResult.ToRebalance = true } rebalanceFilter := map[string]string{poolMetadataName: pool} if !sResult.ToRebalance { // No action yet, check if we need rebalance _, gap, err := a.provisioner.containerGapInNodes(nodes) if err != nil { return errors.Wrapf(err, "unable to obtain container gap in nodes") } buf := safe.NewBuffer(nil) dryProvisioner, err := a.provisioner.rebalanceContainersByFilter(buf, nil, rebalanceFilter, true) if err != nil { return errors.Wrapf(err, "unable to run dry rebalance to check if rebalance is needed. log: %s", buf.String()) } if dryProvisioner == nil { return nil } _, gapAfter, err := dryProvisioner.containerGapInNodes(nodes) if err != nil { return errors.Wrap(err, "couldn't find containers from rebalanced nodes") } if math.Abs((float64)(gap-gapAfter)) > 2.0 { sResult.ToRebalance = true if sResult.Reason == "" { sResult.Reason = fmt.Sprintf("gap is %d, after rebalance gap will be %d", gap, gapAfter) } } } if sResult.ToRebalance { evt.Logf("running rebalance, for %q: %#v", pool, sResult) buf := safe.NewBuffer(nil) writer := io.MultiWriter(buf, evt) _, err := a.provisioner.rebalanceContainersByFilter(writer, nil, rebalanceFilter, false) if err != nil { return errors.Wrapf(err, "unable to rebalance containers. log: %s", buf.String()) } } return nil }
func (s *S) TestBindAndHealthcheckForward(c *check.C) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/x/y" { w.WriteHeader(http.StatusOK) } })) defer server.Close() appName := "my-fake-app" customData := map[string]interface{}{ "healthcheck": map[string]interface{}{ "path": "/x/y", "status": http.StatusOK, }, "processes": map[string]interface{}{ "web": "python myapp.py", "worker": "python myworker.py", }, } err := s.newFakeImage(s.p, "tsuru/app-"+appName, customData) c.Assert(err, check.IsNil) fakeApp := provisiontest.NewFakeApp(appName, "python", 0) s.p.Provision(fakeApp) defer s.p.Destroy(fakeApp) buf := safe.NewBuffer(nil) args := changeUnitsPipelineArgs{ app: fakeApp, provisioner: s.p, writer: buf, toAdd: map[string]*containersToAdd{"web": {Quantity: 2}, "worker": {Quantity: 1}}, imageId: "tsuru/app-" + appName, } containers, err := addContainersWithHost(&args) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 3) url, _ := url.Parse(server.URL) host, port, _ := net.SplitHostPort(url.Host) for i := range containers { if containers[i].ProcessName == "web" { containers[i].HostAddr = host containers[i].HostPort = port } } context := action.FWContext{Params: []interface{}{args}, Previous: containers} result, err := bindAndHealthcheck.Forward(context) c.Assert(err, check.IsNil) resultContainers := result.([]container.Container) c.Assert(resultContainers, check.DeepEquals, containers) u1 := containers[0].AsUnit(fakeApp) u2 := containers[1].AsUnit(fakeApp) c.Assert(fakeApp.HasBind(&u1), check.Equals, true) c.Assert(fakeApp.HasBind(&u2), check.Equals, true) }
func (s *S) TestMoveContainers(c *check.C) { p, err := s.startMultipleServersCluster() c.Assert(err, check.IsNil) err = s.newFakeImage(p, "tsuru/app-myapp", nil) c.Assert(err, check.IsNil) appInstance := provisiontest.NewFakeApp("myapp", "python", 0) defer p.Destroy(appInstance) p.Provision(appInstance) coll := p.Collection() defer coll.Close() coll.Insert(container.Container{ ID: "container-id", AppName: appInstance.GetName(), Version: "container-version", Image: "tsuru/python", }) defer coll.RemoveAll(bson.M{"appname": appInstance.GetName()}) imageId, err := image.AppCurrentImageName(appInstance.GetName()) c.Assert(err, check.IsNil) _, err = addContainersWithHost(&changeUnitsPipelineArgs{ toHost: "localhost", toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, app: appInstance, imageId: imageId, provisioner: p, }) c.Assert(err, check.IsNil) appStruct := &app.App{ Name: appInstance.GetName(), } err = s.storage.Apps().Insert(appStruct) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = p.MoveContainers("localhost", "127.0.0.1", buf) c.Assert(err, check.IsNil) containers, err := p.listContainersByHost("localhost") c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 0) containers, err = p.listContainersByHost("127.0.0.1") c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 2) parts := strings.Split(buf.String(), "\n") c.Assert(parts[0], check.Matches, ".*Moving 2 units.*") var matches int movingRegexp := regexp.MustCompile(`.*Moving unit.*for.*myapp.*localhost.*127.0.0.1.*`) for _, line := range parts[1:] { if movingRegexp.MatchString(line) { matches++ } } c.Assert(matches, check.Equals, 2) }
func (s *S) TestEnsureContainersStartedGracefullyStop(c *check.C) { config.Set("docker:bs:image", "myregistry/tsuru/bs") _, err := nodecontainer.InitializeBS() c.Assert(err, check.IsNil) var reqs []*http.Request server, err := testing.NewServer("127.0.0.1:0", nil, func(r *http.Request) { reqs = append(reqs, r) }) c.Assert(err, check.IsNil) defer server.Stop() p, err := dockertest.NewFakeDockerProvisioner(server.URL()) c.Assert(err, check.IsNil) defer p.Destroy() client, err := docker.NewClient(server.URL()) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) var paths []string for _, r := range reqs { paths = append(paths, r.Method+" "+r.URL.Path) } c.Assert(paths, check.DeepEquals, []string{ "POST /images/create", "POST /containers/create", "GET /version", "POST /containers/big-sibling/start", }) reqs = nil err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) paths = nil for _, r := range reqs { paths = append(paths, r.Method+" "+r.URL.Path) } c.Assert(paths, check.DeepEquals, []string{ "POST /images/create", "POST /containers/create", "POST /containers/big-sibling/stop", "DELETE /containers/big-sibling", "POST /containers/create", "GET /version", "POST /containers/big-sibling/start", }) c.Assert(reqs[3].URL.Query().Get("force"), check.Equals, "") containers, err := client.ListContainers(docker.ListContainersOptions{All: true}) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) container, err := client.InspectContainer(containers[0].ID) c.Assert(err, check.IsNil) c.Assert(container.Name, check.Equals, nodecontainer.BsDefaultName) }
func (s *S) TestEnsureContainersStartedAlreadyPinned(c *check.C) { config.Set("docker:bs:image", "myregistry/tsuru/bs") _, err := nodecontainer.InitializeBS() c.Assert(err, check.IsNil) cont, err := nodecontainer.LoadNodeContainer("", nodecontainer.BsDefaultName) c.Assert(err, check.IsNil) cont.PinnedImage = "myregistry/tsuru/bs@" + digest err = nodecontainer.AddNewContainer("", cont) c.Assert(err, check.IsNil) server, err := testing.NewServer("127.0.0.1:0", nil, nil) c.Assert(err, check.IsNil) defer server.Stop() server.CustomHandler("/images/create", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) server.DefaultHandler().ServeHTTP(w, r) w.Write([]byte(pullOutputDigest)) })) p, err := dockertest.NewFakeDockerProvisioner(server.URL()) c.Assert(err, check.IsNil) defer p.Destroy() client, err := docker.NewClient(server.URL()) c.Assert(err, check.IsNil) err = client.PullImage(docker.PullImageOptions{ Repository: "base", }, docker.AuthConfiguration{}) c.Assert(err, check.IsNil) _, err = client.CreateContainer(docker.CreateContainerOptions{ Name: nodecontainer.BsDefaultName, Config: &docker.Config{Image: "base"}, HostConfig: &docker.HostConfig{}, }) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) containers, err := client.ListContainers(docker.ListContainersOptions{All: true}) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 1) container, err := client.InspectContainer(containers[0].ID) c.Assert(err, check.IsNil) c.Assert(container.Name, check.Equals, nodecontainer.BsDefaultName) c.Assert(container.Config.Image, check.Equals, "myregistry/tsuru/bs@"+digest) c.Assert(container.HostConfig.RestartPolicy, check.Equals, docker.AlwaysRestart()) c.Assert(container.State.Running, check.Equals, true) nodeContainer, err := nodecontainer.LoadNodeContainer("", nodecontainer.BsDefaultName) c.Assert(err, check.IsNil) c.Assert(nodeContainer.PinnedImage, check.Equals, "myregistry/tsuru/bs@"+digest) }
func (s *S) TestBindAndHealthcheckForwardHealthcheckError(c *check.C) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) })) defer server.Close() dbApp := &app.App{Name: "myapp"} err := s.storage.Apps().Insert(dbApp) c.Assert(err, check.IsNil) imageName := "tsuru/app-" + dbApp.Name customData := map[string]interface{}{ "healthcheck": map[string]interface{}{ "path": "/x/y", "status": http.StatusOK, }, "processes": map[string]interface{}{ "web": "python start_app.py", }, } err = s.newFakeImage(s.p, imageName, customData) c.Assert(err, check.IsNil) fakeApp := provisiontest.NewFakeApp(dbApp.Name, "python", 0) s.p.Provision(fakeApp) defer s.p.Destroy(fakeApp) buf := safe.NewBuffer(nil) args := changeUnitsPipelineArgs{ app: fakeApp, provisioner: s.p, writer: buf, toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, imageId: "tsuru/app-" + dbApp.Name, } containers, err := addContainersWithHost(&args) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 2) url, _ := url.Parse(server.URL) host, port, _ := net.SplitHostPort(url.Host) containers[0].HostAddr = host containers[0].HostPort = port containers[1].HostAddr = host containers[1].HostPort = port context := action.FWContext{Params: []interface{}{args}, Previous: containers} _, err = bindAndHealthcheck.Forward(context) c.Assert(err, check.ErrorMatches, `healthcheck fail\(.*?\): wrong status code, expected 200, got: 404`) u1 := containers[0].AsUnit(fakeApp) u2 := containers[1].AsUnit(fakeApp) c.Assert(fakeApp.HasBind(&u1), check.Equals, false) c.Assert(fakeApp.HasBind(&u2), check.Equals, false) }
func (s *S) TestEventDoneLogError(c *check.C) { logBuf := safe.NewBuffer(nil) log.SetLogger(log.NewWriterLogger(logBuf, false)) defer log.SetLogger(nil) evt, err := New(&Opts{ Target: Target{Type: "app", Value: "myapp"}, Kind: permission.PermAppUpdateEnvSet, Owner: s.token, Allowed: Allowed(permission.PermAppReadEvents), }) c.Assert(err, check.IsNil) config.Set("database:url", "127.0.0.1:99999") err = evt.Done(nil) c.Assert(err, check.ErrorMatches, "no reachable servers") c.Assert(logBuf.String(), check.Matches, `(?s).*\[events\] error marking event as done - .*: no reachable servers.*`) }
func (s *S) TestBindAndHealthcheckForwardRestartError(c *check.C) { s.server.CustomHandler("/exec/.*/json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(`{"ID":"id","ExitCode":9}`)) })) conn, err := db.Conn() c.Assert(err, check.IsNil) defer conn.Close() dbApp := &app.App{Name: "myapp"} err = conn.Apps().Insert(dbApp) c.Assert(err, check.IsNil) defer conn.Apps().Remove(bson.M{"name": dbApp.Name}) imageName := "tsuru/app-" + dbApp.Name customData := map[string]interface{}{ "hooks": map[string]interface{}{ "restart": map[string]interface{}{ "after": []string{"will fail"}, }, }, "procfile": "web: python myapp.py", } err = s.newFakeImage(s.p, imageName, customData) c.Assert(err, check.IsNil) fakeApp := provisiontest.NewFakeApp(dbApp.Name, "python", 0) s.p.Provision(fakeApp) defer s.p.Destroy(fakeApp) buf := safe.NewBuffer(nil) args := changeUnitsPipelineArgs{ app: fakeApp, provisioner: s.p, writer: buf, toAdd: map[string]*containersToAdd{"web": {Quantity: 2}}, imageId: "tsuru/app-" + dbApp.Name, } containers, err := addContainersWithHost(&args) c.Assert(err, check.IsNil) c.Assert(containers, check.HasLen, 2) context := action.FWContext{Params: []interface{}{args}, Previous: containers} _, err = bindAndHealthcheck.Forward(context) c.Assert(err, check.ErrorMatches, `couldn't execute restart:after hook "will fail"\(.+?\): unexpected exit code: 9`) u1 := containers[0].asUnit(fakeApp) u2 := containers[1].asUnit(fakeApp) c.Assert(fakeApp.HasBind(&u1), check.Equals, false) c.Assert(fakeApp.HasBind(&u2), check.Equals, false) }
func (a *autoScaleConfig) removeMultipleNodes(event *autoScaleEvent, chosenNodes []cluster.Node) error { nodeAddrs := make([]string, len(chosenNodes)) nodeHosts := make([]string, len(chosenNodes)) for i, node := range chosenNodes { _, hasIaas := node.Metadata["iaas"] if !hasIaas { return fmt.Errorf("no IaaS information in node (%s) metadata: %#v", node.Address, node.Metadata) } nodeAddrs[i] = node.Address nodeHosts[i] = urlToHost(node.Address) } err := a.provisioner.Cluster().UnregisterNodes(nodeAddrs...) if err != nil { return fmt.Errorf("unable to unregister nodes (%s) for removal: %s", strings.Join(nodeAddrs, ", "), err) } buf := safe.NewBuffer(nil) err = a.provisioner.moveContainersFromHosts(nodeHosts, "", buf) if err != nil { for _, node := range chosenNodes { a.provisioner.Cluster().Register(node) } return fmt.Errorf("unable to move containers from nodes (%s): %s - log: %s", strings.Join(nodeAddrs, ", "), err, buf.String()) } wg := sync.WaitGroup{} for i := range chosenNodes { wg.Add(1) go func(i int) { defer wg.Done() node := chosenNodes[i] m, err := iaas.FindMachineByIdOrAddress(node.Metadata["iaas-id"], urlToHost(node.Address)) if err != nil { event.logMsg("unable to find machine for removal in iaas: %s", err) return } err = m.Destroy() if err != nil { event.logMsg("unable to destroy machine in IaaS: %s", err) } }(i) } wg.Wait() return nil }
func (s *S) TestEnsureContainersStartedPinImgInChild(c *check.C) { err := nodecontainer.AddNewContainer("", &nodecontainer.NodeContainerConfig{ Name: "c1", Config: docker.Config{ Image: "myrootimg", }, }) c.Assert(err, check.IsNil) err = nodecontainer.AddNewContainer("p1", &nodecontainer.NodeContainerConfig{ Name: "c1", Config: docker.Config{ Image: "myregistry/tsuru/bs", }, }) c.Assert(err, check.IsNil) server, err := testing.NewServer("127.0.0.1:0", nil, nil) c.Assert(err, check.IsNil) defer server.Stop() server.CustomHandler("/images/create", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) server.DefaultHandler().ServeHTTP(w, r) w.Write([]byte(pullOutputDigest)) })) p, err := dockertest.NewFakeDockerProvisioner(server.URL()) c.Assert(err, check.IsNil) defer p.Destroy() node, err := p.Cluster().GetNode(server.URL()) c.Assert(err, check.IsNil) node.Metadata["pool"] = "p1" _, err = p.Cluster().UpdateNode(node) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) err = ensureContainersStarted(p, buf, true, nil) c.Assert(err, check.IsNil) all, err := nodecontainer.LoadNodeContainersForPoolsMerge("c1", false) c.Assert(err, check.IsNil) c.Assert(all, check.DeepEquals, map[string]nodecontainer.NodeContainerConfig{ "": {Name: "c1", PinnedImage: "", Config: docker.Config{Image: "myrootimg"}}, "p1": {Name: "c1", PinnedImage: "myregistry/tsuru/bs@" + digest, Config: docker.Config{Image: "myregistry/tsuru/bs"}}, }) }
func (s *S) TestDeploy(c *gocheck.C) { h := &tsrTesting.TestHandler{} gandalfServer := tsrTesting.StartGandalfTestServer(h) defer gandalfServer.Close() go s.stopContainers(1) err := newImage("tsuru/python", s.server.URL()) c.Assert(err, gocheck.IsNil) setExecut(&etesting.FakeExecutor{}) defer setExecut(nil) p := dockerProvisioner{} a := app.App{ Name: "otherapp", Platform: "python", } conn, err := db.Conn() defer conn.Close() err = conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer conn.Apps().Remove(bson.M{"name": a.Name}) p.Provision(&a) defer p.Destroy(&a) w := safe.NewBuffer(make([]byte, 2048)) var serviceBodies []string rollback := s.addServiceInstance(c, a.Name, func(w http.ResponseWriter, r *http.Request) { data, _ := ioutil.ReadAll(r.Body) serviceBodies = append(serviceBodies, string(data)) w.WriteHeader(http.StatusOK) }) defer rollback() err = app.Deploy(app.DeployOptions{ App: &a, Version: "master", Commit: "123", OutputStream: w, }) c.Assert(err, gocheck.IsNil) units := a.Units() c.Assert(units, gocheck.HasLen, 1) c.Assert(serviceBodies, gocheck.HasLen, 1) c.Assert(serviceBodies[0], gocheck.Matches, ".*unit-host="+units[0].Ip) }
func (s *S) TestDeployEnqueuesBindService(c *gocheck.C) { h := &tsrTesting.TestHandler{} gandalfServer := tsrTesting.StartGandalfTestServer(h) defer gandalfServer.Close() go s.stopContainers(1) err := newImage("tsuru/python", s.server.URL()) c.Assert(err, gocheck.IsNil) setExecut(&etesting.FakeExecutor{}) defer setExecut(nil) p := dockerProvisioner{} app.Provisioner = &p a := app.App{ Name: "otherapp", Platform: "python", } conn, err := db.Conn() defer conn.Close() err = conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer conn.Apps().Remove(bson.M{"name": a.Name}) p.Provision(&a) defer p.Destroy(&a) w := safe.NewBuffer(make([]byte, 2048)) err = app.Deploy(app.DeployOptions{ App: &a, Version: "master", Commit: "123", OutputStream: w, }) c.Assert(err, gocheck.IsNil) defer p.Destroy(&a) q, err := getQueue() c.Assert(err, gocheck.IsNil) for _, u := range a.Units() { message, err := q.Get(1e6) c.Assert(err, gocheck.IsNil) c.Assert(message.Action, gocheck.Equals, app.BindService) c.Assert(message.Args[0], gocheck.Equals, a.GetName()) c.Assert(message.Args[1], gocheck.Equals, u.Name) } }
func (s *S) TestFollowLogsAndCommitForwardNonZeroStatus(c *check.C) { err := s.newFakeImage(s.p, "tsuru/python", nil) c.Assert(err, check.IsNil) app := provisiontest.NewFakeApp("myapp", "python", 1) cont := container.Container{AppName: "mightyapp"} err = cont.Create(&container.CreateArgs{ App: app, ImageID: "tsuru/python", Commands: []string{"foo"}, Provisioner: s.p, }) c.Assert(err, check.IsNil) err = s.server.MutateContainer(cont.ID, docker.State{ExitCode: 1}) c.Assert(err, check.IsNil) buf := safe.NewBuffer(nil) args := runContainerActionsArgs{writer: buf, provisioner: s.p} context := action.FWContext{Params: []interface{}{args}, Previous: cont} imageId, err := followLogsAndCommit.Forward(context) c.Assert(err, check.NotNil) c.Assert(err.Error(), check.Equals, "Exit status 1") c.Assert(imageId, check.IsNil) }