func (s *S) TestGetImageCustomDataLegacyProcesses(c *check.C) { data := image.ImageMetadata{ Name: "tsuru/app-myapp:v1", LegacyProcesses: map[string]string{ "worker1": "python myapp.py", "worker2": "worker2", }, } err := data.Save() c.Assert(err, check.IsNil) dbMetadata, err := image.GetImageCustomData(data.Name) c.Assert(err, check.IsNil) c.Assert(dbMetadata.Processes, check.DeepEquals, map[string][]string{ "worker1": {"python myapp.py"}, "worker2": {"worker2"}, }) data.Name = "tsuru/app-myapp:v2" data.Processes = map[string][]string{ "w1": {"has", "priority"}, } err = data.Save() c.Assert(err, check.IsNil) dbMetadata, err = image.GetImageCustomData(data.Name) c.Assert(err, check.IsNil) c.Assert(dbMetadata.Processes, check.DeepEquals, map[string][]string{ "w1": {"has", "priority"}, }) }
func (p *dockerProvisioner) deploy(a provision.App, imageId string, evt *event.Event) error { if err := checkCanceled(evt); err != nil { return err } containers, err := p.listContainersByApp(a.GetName()) if err != nil { return err } imageData, err := image.GetImageCustomData(imageId) if err != nil { return err } if len(containers) == 0 { toAdd := make(map[string]*containersToAdd, len(imageData.Processes)) for processName := range imageData.Processes { _, ok := toAdd[processName] if !ok { ct := containersToAdd{Quantity: 0} toAdd[processName] = &ct } toAdd[processName].Quantity++ } if err = setQuota(a, toAdd); err != nil { return err } _, err = p.runCreateUnitsPipeline(evt, a, toAdd, imageId, imageData.ExposedPort) } else { toAdd := getContainersToAdd(imageData, containers) if err = setQuota(a, toAdd); err != nil { return err } _, err = p.runReplaceUnitsPipeline(evt, a, toAdd, containers, imageId) } return err }
func (s *S) TestSavePortInImageCustomData(c *check.C) { img1 := "tsuru/app-myapp:v1" customData1 := map[string]interface{}{ "exposedPort": "3434", } err := image.SaveImageCustomData(img1, customData1) c.Assert(err, check.IsNil) imageMetaData, err := image.GetImageCustomData(img1) c.Check(err, check.IsNil) c.Check(imageMetaData.ExposedPort, check.Equals, "3434") }
func deployProcesses(client *docker.Client, a provision.App, newImg string, updateSpec processSpec) error { curImg, err := image.AppCurrentImageName(a.GetName()) if err != nil { return err } currentImageData, err := image.GetImageCustomData(curImg) if err != nil { return err } currentSpec := processSpec{} for p := range currentImageData.Processes { currentSpec[p] = processState{} } newImageData, err := image.GetImageCustomData(newImg) if err != nil { return err } if len(newImageData.Processes) == 0 { return errors.Errorf("no process information found deploying image %q", newImg) } newSpec := processSpec{} for p := range newImageData.Processes { newSpec[p] = processState{start: true} if updateSpec != nil { newSpec[p] = updateSpec[p] } } pipeline := action.NewPipeline( updateServices, updateImageInDB, removeOldServices, ) return pipeline.Execute(&pipelineArgs{ client: client, app: a, newImage: newImg, newImageSpec: newSpec, currentImage: curImg, currentImageSpec: currentSpec, }) }
func (s *S) TestPrepareImageForDeployNoProcfile(c *check.C) { srv, err := testing.NewServer("0.0.0.0:0", nil, nil) c.Assert(err, check.IsNil) defer srv.Stop() a := &app.App{Name: "myapp"} cli, err := docker.NewClient(srv.URL()) c.Assert(err, check.IsNil) baseImgName := "baseImg" err = cli.PullImage(docker.PullImageOptions{Repository: baseImgName}, docker.AuthConfiguration{}) c.Assert(err, check.IsNil) srv.CustomHandler(fmt.Sprintf("/images/%s/json", baseImgName), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { response := docker.Image{ Config: &docker.Config{ Entrypoint: []string{"/bin/sh"}, Cmd: []string{"python", "test file.py"}, ExposedPorts: map[docker.Port]struct{}{"3000/tcp": {}}, }, } j, _ := json.Marshal(response) w.Write(j) })) buf := bytes.Buffer{} args := PrepareImageArgs{ Client: cli, App: a, ProcfileRaw: "", ImageId: baseImgName, Out: &buf, } newImg, err := PrepareImageForDeploy(args) c.Assert(err, check.IsNil) c.Assert(newImg, check.Equals, "my.registry/tsuru/app-myapp:v1") c.Assert(buf.String(), check.Equals, `---- Inspecting image "baseImg" ---- ---> Procfile not found, using entrypoint and cmd ---> Process "web" found with commands: ["/bin/sh" "python" "test file.py"] ---- Pushing image "my.registry/tsuru/app-myapp:v1" to tsuru ---- Pushing... Pushed `) imd, err := image.GetImageCustomData(newImg) c.Assert(err, check.IsNil) c.Assert(imd, check.DeepEquals, image.ImageMetadata{ Name: "my.registry/tsuru/app-myapp:v1", Processes: map[string][]string{"web": {"/bin/sh", "python", "test file.py"}}, CustomData: map[string]interface{}{}, LegacyProcesses: map[string]string{}, ExposedPort: "3000/tcp", }) }
func allAppProcesses(appName string) ([]string, error) { var processes []string imgID, err := image.AppCurrentImageName(appName) if err != nil { return nil, errors.WithStack(err) } data, err := image.GetImageCustomData(imgID) if err != nil { return nil, errors.WithStack(err) } for procName := range data.Processes { processes = append(processes, procName) } return processes, nil }
func (s *S) TestSaveImageCustomDataProcfile(c *check.C) { img1 := "tsuru/app-myapp:v1" customData1 := map[string]interface{}{ "exposedPort": "3434", "procfile": "worker1: python myapp.py\nworker2: someworker", } err := image.SaveImageCustomData(img1, customData1) c.Assert(err, check.IsNil) imageMetaData, err := image.GetImageCustomData(img1) c.Check(err, check.IsNil) c.Check(imageMetaData.ExposedPort, check.Equals, "3434") c.Check(imageMetaData.Processes, check.DeepEquals, map[string][]string{ "worker1": {"python myapp.py"}, "worker2": {"someworker"}, }) }
func ProcessCmdForImage(processName, imageId string) ([]string, string, error) { data, err := image.GetImageCustomData(imageId) if err != nil { return nil, "", err } if processName == "" { if len(data.Processes) == 0 { return nil, "", nil } if len(data.Processes) > 1 { return nil, "", provision.InvalidProcessError{Msg: "no process name specified and more than one declared in Procfile"} } for name := range data.Processes { processName = name } } processCmd := data.Processes[processName] if len(processCmd) == 0 { return nil, "", provision.InvalidProcessError{Msg: fmt.Sprintf("no command declared in Procfile for process %q", processName)} } return processCmd, processName, nil }
func (p *dockerProvisioner) AddUnits(a provision.App, units uint, process string, w io.Writer) error { if a.GetDeploys() == 0 { return errors.New("New units can only be added after the first deployment") } if units == 0 { return errors.New("Cannot add 0 units") } if w == nil { w = ioutil.Discard } writer := io.MultiWriter(w, &app.LogWriter{App: a}) imageId, err := image.AppCurrentImageName(a.GetName()) if err != nil { return err } imageData, err := image.GetImageCustomData(imageId) if err != nil { return err } _, err = p.runCreateUnitsPipeline(writer, a, map[string]*containersToAdd{process: {Quantity: int(units)}}, imageId, imageData.ExposedPort) return err }
func (s *S) TestPrepareImageForDeploy(c *check.C) { srv, err := testing.NewServer("0.0.0.0:0", nil, nil) c.Assert(err, check.IsNil) defer srv.Stop() a := &app.App{Name: "myapp"} cli, err := docker.NewClient(srv.URL()) c.Assert(err, check.IsNil) baseImgName := "baseImg" err = cli.PullImage(docker.PullImageOptions{Repository: baseImgName}, docker.AuthConfiguration{}) c.Assert(err, check.IsNil) buf := bytes.Buffer{} args := PrepareImageArgs{ Client: cli, App: a, ProcfileRaw: "web: myapp run", ImageId: baseImgName, Out: &buf, } newImg, err := PrepareImageForDeploy(args) c.Assert(err, check.IsNil) c.Assert(newImg, check.Equals, "my.registry/tsuru/app-myapp:v1") c.Assert(buf.String(), check.Equals, `---- Inspecting image "baseImg" ---- ---> Process "web" found with commands: ["myapp run"] ---- Pushing image "my.registry/tsuru/app-myapp:v1" to tsuru ---- Pushing... Pushed `) imd, err := image.GetImageCustomData(newImg) c.Assert(err, check.IsNil) c.Assert(imd, check.DeepEquals, image.ImageMetadata{ Name: "my.registry/tsuru/app-myapp:v1", Processes: map[string][]string{"web": {"myapp run"}}, CustomData: map[string]interface{}{}, LegacyProcesses: map[string]string{}, }) }