本文整理匯總了Golang中github.com/flynn/flynn/controller/client.PutFormation函數的典型用法代碼示例。如果您正苦於以下問題:Golang PutFormation函數的具體用法?Golang PutFormation怎麽用?Golang PutFormation使用的例子?那麽, 這裏精選的函數代碼示例或許可以為您提供幫助。
在下文中一共展示了PutFormation函數的15個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: FixController
func (f *ClusterFixer) FixController(instances []*discoverd.Instance, startScheduler bool) error {
f.l.Info("found controller instance, checking critical formations")
inst := instances[0]
client, err := controller.NewClient("http://"+inst.Addr, inst.Meta["AUTH_KEY"])
if err != nil {
return fmt.Errorf("unexpected error creating controller client: %s", err)
}
// check that formations for critical components are expected
apps := []string{"controller", "router", "discoverd", "flannel", "postgres"}
changes := make(map[string]*ct.Formation, len(apps))
var controllerFormation *ct.Formation
for _, app := range apps {
release, err := client.GetAppRelease(app)
if err != nil {
return fmt.Errorf("error getting %s release: %s", app, err)
}
formation, err := client.GetFormation(app, release.ID)
if err != nil {
// TODO: handle ErrNotFound
return fmt.Errorf("error getting %s formation: %s", app, err)
}
if app == "controller" {
controllerFormation = formation
}
for typ := range release.Processes {
var want int
if app == "postgres" && typ == "postgres" && len(f.hosts) > 1 && formation.Processes[typ] < 3 {
want = 3
} else if formation.Processes[typ] < 1 {
want = 1
}
if want > 0 {
f.l.Info("found broken formation", "app", app, "process", typ)
if _, ok := changes[app]; !ok {
if formation.Processes == nil {
formation.Processes = make(map[string]int)
}
changes[app] = formation
}
changes[app].Processes[typ] = want
}
}
}
for app, formation := range changes {
f.l.Info("fixing broken formation", "app", app)
if err := client.PutFormation(formation); err != nil {
return fmt.Errorf("error putting %s formation: %s", app, err)
}
}
if startScheduler {
if err := f.StartScheduler(client, controllerFormation); err != nil {
return err
}
}
return nil
}
示例2: TestReleaseDelete
func (s *CLISuite) TestReleaseDelete(t *c.C) {
// create an app and release it twice
r := s.newGitRepo(t, "http")
app := "release-delete-" + random.String(8)
t.Assert(r.flynn("create", app), Succeeds)
t.Assert(r.git("push", "flynn", "master"), Succeeds)
t.Assert(r.git("commit", "--allow-empty", "--message", "empty commit"), Succeeds)
t.Assert(r.git("push", "flynn", "master"), Succeeds)
// get the releases
client := s.controllerClient(t)
releases, err := client.AppReleaseList(app)
t.Assert(err, c.IsNil)
t.Assert(releases, c.HasLen, 2)
// check the current release cannot be deleted
res := r.flynn("release", "delete", "--yes", releases[0].ID)
t.Assert(res, c.Not(Succeeds))
t.Assert(res.Output, c.Equals, "validation_error: cannot delete current app release\n")
// associate the initial release with another app
otherApp := &ct.App{Name: "release-delete-" + random.String(8)}
t.Assert(client.CreateApp(otherApp), c.IsNil)
t.Assert(client.PutFormation(&ct.Formation{AppID: otherApp.ID, ReleaseID: releases[1].ID}), c.IsNil)
// check deleting the initial release just deletes the formation
res = r.flynn("release", "delete", "--yes", releases[1].ID)
t.Assert(res, Succeeds)
t.Assert(res.Output, c.Equals, "Release scaled down for app but not fully deleted (still associated with 1 other apps)\n")
// check the slug artifact still exists
slugArtifact, err := client.GetArtifact(releases[1].ArtifactIDs[1])
t.Assert(err, c.IsNil)
s.assertURI(t, slugArtifact.URI, http.StatusOK)
slugLayerURL := slugArtifact.LayerURL(slugArtifact.Manifest().Rootfs[0].Layers[0])
s.assertURI(t, slugLayerURL, http.StatusOK)
// check the inital release can now be deleted
res = r.flynn("-a", otherApp.ID, "release", "delete", "--yes", releases[1].ID)
t.Assert(res, Succeeds)
t.Assert(res.Output, c.Equals, fmt.Sprintf("Deleted release %s (deleted 2 files)\n", releases[1].ID))
// check the slug artifact was deleted
_, err = client.GetArtifact(slugArtifact.ID)
t.Assert(err, c.Equals, controller.ErrNotFound)
s.assertURI(t, slugArtifact.URI, http.StatusNotFound)
s.assertURI(t, slugLayerURL, http.StatusNotFound)
// check the image artifact was not deleted (since it is shared between both releases)
_, err = client.GetArtifact(releases[1].ArtifactIDs[0])
t.Assert(err, c.IsNil)
}
示例3: TestResourceLimitsReleaseJob
func (s *ControllerSuite) TestResourceLimitsReleaseJob(t *c.C) {
client := s.controllerClient(t)
app, release := s.createApp(t)
watcher, err := client.WatchJobEvents(app.ID, release.ID)
t.Assert(err, c.IsNil)
defer watcher.Close()
t.Assert(client.PutFormation(&ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: map[string]int{"resources": 1},
}), c.IsNil)
var jobID string
err = watcher.WaitFor(ct.JobEvents{"resources": {ct.JobStateUp: 1, ct.JobStateDown: 1}}, scaleTimeout, func(e *ct.Job) error {
jobID = e.ID
return nil
})
t.Assert(err, c.IsNil)
log := flynn(t, "/", "-a", app.Name, "log", "--job", jobID, "--raw-output")
assertResourceLimits(t, log.Output)
}
示例4: main
//.........這裏部分代碼省略.........
log.Fatalf("Unknown app %q", appName)
} else if err != nil {
log.Fatalln("Error retrieving app:", err)
}
prevRelease, err := client.GetAppRelease(app.Name)
if err == controller.ErrNotFound {
prevRelease = &ct.Release{}
} else if err != nil {
log.Fatalln("Error getting current app release:", err)
}
fmt.Printf("-----> Building %s...\n", app.Name)
var output bytes.Buffer
slugURL := fmt.Sprintf("%s/%s.tgz", blobstoreURL, random.UUID())
cmd := exec.Command(exec.DockerImage(os.Getenv("SLUGBUILDER_IMAGE_URI")), slugURL)
cmd.Stdout = io.MultiWriter(os.Stdout, &output)
cmd.Stderr = os.Stderr
if len(prevRelease.Env) > 0 {
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatalln(err)
}
go appendEnvDir(os.Stdin, stdin, prevRelease.Env)
} else {
cmd.Stdin = os.Stdin
}
cmd.Env = make(map[string]string)
cmd.Env["BUILD_CACHE_URL"] = fmt.Sprintf("%s/%s-cache.tgz", blobstoreURL, app.ID)
if buildpackURL, ok := prevRelease.Env["BUILDPACK_URL"]; ok {
cmd.Env["BUILDPACK_URL"] = buildpackURL
}
if err := cmd.Run(); err != nil {
log.Fatalln("Build failed:", err)
}
var types []string
if match := typesPattern.FindSubmatch(output.Bytes()); match != nil {
types = strings.Split(string(match[1]), ", ")
}
fmt.Printf("-----> Creating release...\n")
artifact := &ct.Artifact{Type: "docker", URI: os.Getenv("SLUGRUNNER_IMAGE_URI")}
if err := client.CreateArtifact(artifact); err != nil {
log.Fatalln("Error creating artifact:", err)
}
release := &ct.Release{
ArtifactID: artifact.ID,
Env: prevRelease.Env,
}
procs := make(map[string]ct.ProcessType)
for _, t := range types {
proc := prevRelease.Processes[t]
proc.Cmd = []string{"start", t}
if t == "web" {
proc.Ports = []ct.Port{{
Port: 8080,
Proto: "tcp",
Service: &host.Service{
Name: app.Name + "-web",
Create: true,
Check: &host.HealthCheck{Type: "tcp"},
},
}}
}
procs[t] = proc
}
release.Processes = procs
if release.Env == nil {
release.Env = make(map[string]string)
}
release.Env["SLUG_URL"] = slugURL
if err := client.CreateRelease(release); err != nil {
log.Fatalln("Error creating release:", err)
}
if err := client.DeployAppRelease(app.Name, release.ID); err != nil {
log.Fatalln("Error deploying app release:", err)
}
fmt.Println("=====> Application deployed")
// If the app is new and the web process type exists,
// it should scale to one process after the release is created.
if _, ok := procs["web"]; ok && prevRelease.ID == "" {
formation := &ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: map[string]int{"web": 1},
}
if err := client.PutFormation(formation); err != nil {
log.Fatalln("Error putting formation:", err)
}
fmt.Println("=====> Added default web=1 formation")
}
}
示例5: TestSlugReleaseGarbageCollection
func (s *CLISuite) TestSlugReleaseGarbageCollection(t *c.C) {
client := s.controllerClient(t)
// create app with gc.max_inactive_slug_releases=3
maxInactiveSlugReleases := 3
app := &ct.App{Meta: map[string]string{"gc.max_inactive_slug_releases": strconv.Itoa(maxInactiveSlugReleases)}}
t.Assert(client.CreateApp(app), c.IsNil)
// create an image artifact
imageArtifact := s.createArtifact(t, "test-apps")
// create 5 slug artifacts
tmp, err := ioutil.TempFile("", "squashfs-")
t.Assert(err, c.IsNil)
defer os.Remove(tmp.Name())
defer tmp.Close()
t.Assert(exec.Command("mksquashfs", t.MkDir(), tmp.Name(), "-noappend").Run(), c.IsNil)
slug, err := ioutil.ReadAll(tmp)
t.Assert(err, c.IsNil)
slugHash := sha512.Sum512(slug)
slugs := []string{
"http://blobstore.discoverd/layer/1.squashfs",
"http://blobstore.discoverd/layer/2.squashfs",
"http://blobstore.discoverd/layer/3.squashfs",
"http://blobstore.discoverd/layer/4.squashfs",
"http://blobstore.discoverd/layer/5.squashfs",
}
slugArtifacts := make([]*ct.Artifact, len(slugs))
put := func(url string, data []byte) {
req, err := http.NewRequest("PUT", url, bytes.NewReader(data))
t.Assert(err, c.IsNil)
res, err := http.DefaultClient.Do(req)
t.Assert(err, c.IsNil)
res.Body.Close()
t.Assert(res.StatusCode, c.Equals, http.StatusOK)
}
for i, layerURL := range slugs {
manifest := &ct.ImageManifest{
Type: ct.ImageManifestTypeV1,
Rootfs: []*ct.ImageRootfs{{
Layers: []*ct.ImageLayer{{
ID: strconv.Itoa(i + 1),
Type: ct.ImageLayerTypeSquashfs,
Length: int64(len(slug)),
Hashes: map[string]string{"sha512": hex.EncodeToString(slugHash[:])},
}},
}},
}
data := manifest.RawManifest()
url := fmt.Sprintf("http://blobstore.discoverd/image/%s.json", manifest.ID())
put(url, data)
put(layerURL, slug)
artifact := &ct.Artifact{
Type: ct.ArtifactTypeFlynn,
URI: url,
Meta: map[string]string{"blobstore": "true"},
RawManifest: data,
Hashes: manifest.Hashes(),
Size: int64(len(data)),
LayerURLTemplate: "http://blobstore.discoverd/layer/{id}.squashfs",
}
t.Assert(client.CreateArtifact(artifact), c.IsNil)
slugArtifacts[i] = artifact
}
// create 6 releases, the second being scaled up and having the
// same slug as the third (so prevents the slug being deleted)
releases := make([]*ct.Release, 6)
for i, r := range []struct {
slug *ct.Artifact
active bool
}{
{slugArtifacts[0], false},
{slugArtifacts[1], true},
{slugArtifacts[1], false},
{slugArtifacts[2], false},
{slugArtifacts[3], false},
{slugArtifacts[4], false},
} {
release := &ct.Release{
ArtifactIDs: []string{imageArtifact.ID, r.slug.ID},
Processes: map[string]ct.ProcessType{
"app": {Args: []string{"/bin/pingserv"}, Ports: []ct.Port{{Proto: "tcp"}}},
},
Meta: map[string]string{"git": "true"},
}
t.Assert(client.CreateRelease(release), c.IsNil)
procs := map[string]int{"app": 0}
if r.active {
procs["app"] = 1
}
t.Assert(client.PutFormation(&ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: procs,
}), c.IsNil)
releases[i] = release
}
// scale the last release so we can deploy it
//.........這裏部分代碼省略.........
示例6: TestReleaseImages
func (s *ReleaseSuite) TestReleaseImages(t *c.C) {
if testCluster == nil {
t.Skip("cannot boot release cluster")
}
// stream script output to t.Log
logReader, logWriter := io.Pipe()
defer logWriter.Close()
go func() {
buf := bufio.NewReader(logReader)
for {
line, err := buf.ReadString('\n')
if err != nil {
return
}
debug(t, line[0:len(line)-1])
}
}()
// boot the release cluster, release components to a blobstore and output the new images.json
releaseCluster := s.addReleaseHosts(t)
buildHost := releaseCluster.Instances[0]
var imagesJSON bytes.Buffer
var script bytes.Buffer
slugImageID := random.UUID()
releaseScript.Execute(&script, struct{ ControllerKey, SlugImageID string }{releaseCluster.ControllerKey, slugImageID})
t.Assert(buildHost.Run("bash -ex", &tc.Streams{Stdin: &script, Stdout: &imagesJSON, Stderr: logWriter}), c.IsNil)
var images map[string]*ct.Artifact
t.Assert(json.Unmarshal(imagesJSON.Bytes(), &images), c.IsNil)
// install Flynn from the blobstore on the vanilla host
blobstoreAddr := buildHost.IP + ":8080"
installHost := releaseCluster.Instances[3]
script.Reset()
installScript.Execute(&script, map[string]string{"Blobstore": blobstoreAddr})
var installOutput bytes.Buffer
out := io.MultiWriter(logWriter, &installOutput)
t.Assert(installHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)
// check the flynn-host version is correct
var hostVersion bytes.Buffer
t.Assert(installHost.Run("flynn-host version", &tc.Streams{Stdout: &hostVersion}), c.IsNil)
t.Assert(strings.TrimSpace(hostVersion.String()), c.Equals, "v20161108.0-test")
// check rebuilt images were downloaded
assertInstallOutput := func(format string, v ...interface{}) {
expected := fmt.Sprintf(format, v...)
if !strings.Contains(installOutput.String(), expected) {
t.Fatalf(`expected install to output %q`, expected)
}
}
for name, image := range images {
assertInstallOutput("pulling %s image", name)
for _, layer := range image.Manifest().Rootfs[0].Layers {
assertInstallOutput("pulling %s layer %s", name, layer.ID)
}
}
// installing on an instance with Flynn running should fail
script.Reset()
installScript.Execute(&script, map[string]string{"Blobstore": blobstoreAddr})
installOutput.Reset()
err := buildHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out})
if err == nil || !strings.Contains(installOutput.String(), "ERROR: Flynn is already installed.") {
t.Fatal("expected Flynn install to fail but it didn't")
}
// create a controller client for the release cluster
pin, err := base64.StdEncoding.DecodeString(releaseCluster.ControllerPin)
t.Assert(err, c.IsNil)
client, err := controller.NewClientWithConfig(
"https://"+buildHost.IP,
releaseCluster.ControllerKey,
controller.Config{Pin: pin, Domain: releaseCluster.ControllerDomain},
)
t.Assert(err, c.IsNil)
// deploy a slug based app + Redis resource
slugApp := &ct.App{}
t.Assert(client.CreateApp(slugApp), c.IsNil)
gitreceive, err := client.GetAppRelease("gitreceive")
t.Assert(err, c.IsNil)
imageArtifact, err := client.GetArtifact(gitreceive.Env["SLUGRUNNER_IMAGE_ID"])
t.Assert(err, c.IsNil)
slugArtifact, err := client.GetArtifact(slugImageID)
t.Assert(err, c.IsNil)
resource, err := client.ProvisionResource(&ct.ResourceReq{ProviderID: "redis", Apps: []string{slugApp.ID}})
t.Assert(err, c.IsNil)
release := &ct.Release{
ArtifactIDs: []string{imageArtifact.ID, slugArtifact.ID},
Processes: map[string]ct.ProcessType{"web": {Args: []string{"/runner/init", "bin/http"}}},
Meta: map[string]string{"git": "true"},
Env: resource.Env,
}
t.Assert(client.CreateRelease(release), c.IsNil)
t.Assert(client.SetAppRelease(slugApp.ID, release.ID), c.IsNil)
watcher, err := client.WatchJobEvents(slugApp.ID, release.ID)
t.Assert(err, c.IsNil)
defer watcher.Close()
t.Assert(client.PutFormation(&ct.Formation{
//.........這裏部分代碼省略.........
示例7: runBootstrapBackup
//.........這裏部分代碼省略.........
ExpandedFormation: data.Controller,
}),
}.RunWithState(ch, state)
// wait for controller to come up
meta = bootstrap.StepMeta{ID: "wait-controller", Action: "wait-controller"}
ch <- &bootstrap.StepInfo{StepMeta: meta, State: "start", Timestamp: time.Now().UTC()}
controllerInstances, err := discoverd.GetInstances("controller", 30*time.Second)
if err != nil {
return fmt.Errorf("error getting controller instance: %s", err)
}
controllerKey := data.Controller.Release.Env["AUTH_KEY"]
client, err := controller.NewClient("http://"+controllerInstances[0].Addr, controllerKey)
if err != nil {
return err
}
// start mariadb and load data if it was present in the backup.
mysqldb, err := getFile("mysql.sql.gz")
if err == nil && data.MariaDB != nil {
_, err = bootstrap.Manifest{
step("mariadb", "run-app", &bootstrap.RunAppAction{
ExpandedFormation: data.MariaDB,
}),
step("mariadb-wait", "sirenia-wait", &bootstrap.SireniaWaitAction{
Service: "mariadb",
}),
}.RunWithState(ch, state)
if err != nil {
return err
}
// ensure the formation is correct in the database
if err := client.PutFormation(data.MariaDB.Formation()); err != nil {
return fmt.Errorf("error updating mariadb formation: %s", err)
}
cmd = exec.JobUsingHost(state.Hosts[0], artifacts["mariadb"], nil)
cmd.Args = []string{"mysql", "-u", "flynn", "-h", "leader.mariadb.discoverd"}
cmd.Env = map[string]string{
"MYSQL_PWD": data.MariaDB.Release.Env["MYSQL_PWD"],
}
cmd.Stdin = mysqldb
meta = bootstrap.StepMeta{ID: "restore", Action: "restore-mariadb"}
ch <- &bootstrap.StepInfo{StepMeta: meta, State: "start", Timestamp: time.Now().UTC()}
out, err = cmd.CombinedOutput()
if os.Getenv("DEBUG") != "" {
fmt.Println(string(out))
}
if err != nil {
ch <- &bootstrap.StepInfo{
StepMeta: meta,
State: "error",
Error: fmt.Sprintf("error running mysql restore: %s - %q", err, string(out)),
Err: err,
Timestamp: time.Now().UTC(),
}
return err
}
ch <- &bootstrap.StepInfo{StepMeta: meta, State: "done", Timestamp: time.Now().UTC()}
}
// start mongodb and load data if it was present in the backup.
mongodb, err := getFile("mongodb.archive.gz")
if err == nil && data.MongoDB != nil {
_, err = bootstrap.Manifest{
示例8: main
func main() {
client, err := controller.NewClient("", os.Getenv("CONTROLLER_AUTH_KEY"))
if err != nil {
log.Fatalln("Unable to connect to controller:", err)
}
// TODO: use discoverd http dialer here?
services, err := discoverd.Services("blobstore", discoverd.DefaultTimeout)
if err != nil || len(services) < 1 {
log.Fatalf("Unable to discover blobstore %q", err)
}
blobstoreHost := services[0].Addr
appName := os.Args[1]
app, err := client.GetApp(appName)
if err == controller.ErrNotFound {
log.Fatalf("Unknown app %q", appName)
} else if err != nil {
log.Fatalln("Error retrieving app:", err)
}
prevRelease, err := client.GetAppRelease(app.Name)
if err == controller.ErrNotFound {
prevRelease = &ct.Release{}
} else if err != nil {
log.Fatalln("Error creating getting current app release:", err)
}
fmt.Printf("-----> Building %s...\n", app.Name)
var output bytes.Buffer
slugURL := fmt.Sprintf("http://%s/%s.tgz", blobstoreHost, random.UUID())
cmd := exec.Command(exec.DockerImage("flynn/slugbuilder", os.Getenv("SLUGBUILDER_IMAGE_ID")), slugURL)
cmd.Stdout = io.MultiWriter(os.Stdout, &output)
cmd.Stderr = os.Stderr
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatalln(err)
}
go appendEnvDir(os.Stdin, stdin, prevRelease.Env)
if buildpackURL, ok := prevRelease.Env["BUILDPACK_URL"]; ok {
cmd.Env = map[string]string{"BUILDPACK_URL": buildpackURL}
}
if err := cmd.Run(); err != nil {
log.Fatalln("Build failed:", err)
}
var types []string
if match := typesPattern.FindSubmatch(output.Bytes()); match != nil {
types = strings.Split(string(match[1]), ", ")
}
fmt.Printf("-----> Creating release...\n")
artifact := &ct.Artifact{Type: "docker", URI: "https://registry.hub.docker.com/flynn/slugrunner?id=" + os.Getenv("SLUGRUNNER_IMAGE_ID")}
if err := client.CreateArtifact(artifact); err != nil {
log.Fatalln("Error creating artifact:", err)
}
release := &ct.Release{
ArtifactID: artifact.ID,
Env: prevRelease.Env,
}
procs := make(map[string]ct.ProcessType)
for _, t := range types {
proc := prevRelease.Processes[t]
proc.Cmd = []string{"start", t}
if t == "web" {
proc.Ports = []ct.Port{{Proto: "tcp"}}
if proc.Env == nil {
proc.Env = make(map[string]string)
}
proc.Env["SD_NAME"] = app.Name + "-web"
}
procs[t] = proc
}
release.Processes = procs
if release.Env == nil {
release.Env = make(map[string]string)
}
release.Env["SLUG_URL"] = slugURL
if err := client.CreateRelease(release); err != nil {
log.Fatalln("Error creating release:", err)
}
if err := client.SetAppRelease(app.Name, release.ID); err != nil {
log.Fatalln("Error setting app release:", err)
}
fmt.Println("=====> Application deployed")
// If the app is new and the web process type exists,
// it should scale to one process after the release is created.
if _, ok := procs["web"]; ok && prevRelease.ID == "" {
formation := &ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: map[string]int{"web": 1},
}
if err := client.PutFormation(formation); err != nil {
//.........這裏部分代碼省略.........
示例9: ScaleUp
// ScaleUp scales up a dormant Sirenia cluster
func ScaleUp(app, controllerKey, serviceAddr, procName, singleton string, logger log15.Logger) error {
logger = logger.New("fn", "ScaleUp")
sc := sirenia.NewClient(serviceAddr)
logger.Info("checking status", "host", serviceAddr)
if status, err := sc.Status(); err == nil && status.Database != nil && status.Database.ReadWrite {
logger.Info("database is up, skipping scale")
// Skip the rest, the database is already available
return nil
} else if err != nil {
logger.Info("error checking status", "err", err)
} else {
logger.Info("got status, but database is not read-write")
}
// Connect to controller.
logger.Info("connecting to controller")
client, err := controller.NewClient("", controllerKey)
if err != nil {
logger.Error("controller client error", "err", err)
return err
}
// Retrieve the app release.
logger.Info("retrieving app release", "app", app)
release, err := client.GetAppRelease(app)
if err == controller.ErrNotFound {
logger.Error("release not found", "app", app)
return errors.New("release not found")
} else if err != nil {
logger.Error("get release error", "app", app, "err", err)
return err
}
// Retrieve current formation.
logger.Info("retrieving formation", "app", app, "release_id", release.ID)
formation, err := client.GetFormation(app, release.ID)
if err == controller.ErrNotFound {
logger.Error("formation not found", "app", app, "release_id", release.ID)
return errors.New("formation not found")
} else if err != nil {
logger.Error("formation error", "app", app, "release_id", release.ID, "err", err)
return err
}
// If database is running then exit.
if formation.Processes[procName] > 0 {
logger.Info("database is running, scaling not necessary")
return nil
}
// Copy processes and increase database processes.
processes := make(map[string]int, len(formation.Processes))
for k, v := range formation.Processes {
processes[k] = v
}
if singleton == "true" {
processes[procName] = 1
} else {
processes[procName] = 3
}
// Update formation.
logger.Info("updating formation", "app", app, "release_id", release.ID)
formation.Processes = processes
if err := client.PutFormation(formation); err != nil {
logger.Error("put formation error", "app", app, "release_id", release.ID, "err", err)
return err
}
if err := sc.WaitForReadWrite(5 * time.Minute); err != nil {
logger.Error("wait for read write", "err", err)
return errors.New("timed out while starting sirenia cluster")
}
logger.Info("scaling complete")
return nil
}
示例10: main
//.........這裏部分代碼省略.........
go appendEnvDir(os.Stdin, stdin, prevRelease.Env)
} else {
cmd.Stdin = os.Stdin
}
cmd.Env = make(map[string]string)
cmd.Env["BUILD_CACHE_URL"] = fmt.Sprintf("%s/%s-cache.tgz", blobstoreURL, app.ID)
if buildpackURL, ok := prevRelease.Env["BUILDPACK_URL"]; ok {
cmd.Env["BUILDPACK_URL"] = buildpackURL
}
for _, k := range []string{"SSH_CLIENT_KEY", "SSH_CLIENT_HOSTS"} {
if v := os.Getenv(k); v != "" {
cmd.Env[k] = v
}
}
if err := cmd.Run(); err != nil {
log.Fatalln("Build failed:", err)
}
var types []string
if match := typesPattern.FindSubmatch(output.Bytes()); match != nil {
types = strings.Split(string(match[1]), ", ")
}
fmt.Printf("-----> Creating release...\n")
artifact := &ct.Artifact{Type: "docker", URI: os.Getenv("SLUGRUNNER_IMAGE_URI")}
if err := client.CreateArtifact(artifact); err != nil {
log.Fatalln("Error creating artifact:", err)
}
release := &ct.Release{
ArtifactID: artifact.ID,
Env: prevRelease.Env,
}
procs := make(map[string]ct.ProcessType)
for _, t := range types {
proc := prevRelease.Processes[t]
proc.Cmd = []string{"start", t}
if t == "web" {
proc.Ports = []ct.Port{{
Port: 8080,
Proto: "tcp",
Service: &host.Service{
Name: app.Name + "-web",
Create: true,
Check: &host.HealthCheck{Type: "tcp"},
},
}}
}
procs[t] = proc
}
release.Processes = procs
if release.Env == nil {
release.Env = make(map[string]string)
}
release.Env["SLUG_URL"] = slugURL
if err := client.CreateRelease(release); err != nil {
log.Fatalln("Error creating release:", err)
}
if err := client.DeployAppRelease(app.Name, release.ID); err != nil {
log.Fatalln("Error deploying app release:", err)
}
fmt.Println("=====> Application deployed")
if needsDefaultScale(app.ID, prevRelease.ID, procs, client) {
formation := &ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: map[string]int{"web": 1},
}
watcher, err := client.WatchJobEvents(app.ID, release.ID)
if err != nil {
log.Fatalln("Error streaming job events", err)
return
}
defer watcher.Close()
if err := client.PutFormation(formation); err != nil {
log.Fatalln("Error putting formation:", err)
}
fmt.Println("=====> Waiting for web job to start...")
err = watcher.WaitFor(ct.JobEvents{"web": {"up": 1}}, scaleTimeout, func(e *ct.Job) error {
switch e.State {
case "up":
fmt.Println("=====> Default web formation scaled to 1")
case "down", "crashed":
return fmt.Errorf("Failed to scale web process type")
}
return nil
})
if err != nil {
log.Fatalln(err.Error())
}
}
}
示例11: scaleUp
func (a *API) scaleUp() error {
a.mtx.Lock()
defer a.mtx.Unlock()
// Ignore if already scaled up.
if a.scaledUp {
return nil
}
app := os.Getenv("FLYNN_APP_ID")
logger := a.logger().New("fn", "scaleUp")
sc := sirenia.NewClient(serviceHost + ":3306")
logger.Info("checking status", "host", serviceHost)
if status, err := sc.Status(); err == nil && status.Database != nil && status.Database.ReadWrite {
logger.Info("database is up, skipping scale")
// Skip the rest, the database is already available
a.scaledUp = true
return nil
} else if err != nil {
logger.Info("error checking status", "err", err)
} else {
logger.Info("got status, but database is not read-write")
}
// Connect to controller.
logger.Info("connecting to controller")
client, err := controller.NewClient("", os.Getenv("CONTROLLER_KEY"))
if err != nil {
logger.Error("controller client error", "err", err)
return err
}
// Retrieve mariadb release.
logger.Info("retrieving app release", "app", app)
release, err := client.GetAppRelease(app)
if err == controller.ErrNotFound {
logger.Error("release not found", "app", app)
return errors.New("mariadb release not found")
} else if err != nil {
logger.Error("get release error", "app", app, "err", err)
return err
}
// Retrieve current formation.
logger.Info("retrieving formation", "app", app, "release_id", release.ID)
formation, err := client.GetFormation(app, release.ID)
if err == controller.ErrNotFound {
logger.Error("formation not found", "app", app, "release_id", release.ID)
return errors.New("mariadb formation not found")
} else if err != nil {
logger.Error("formation error", "app", app, "release_id", release.ID, "err", err)
return err
}
// If mariadb is running then exit.
if formation.Processes["mariadb"] > 0 {
logger.Info("database is running, scaling not necessary")
return nil
}
// Copy processes and increase database processes.
processes := make(map[string]int, len(formation.Processes))
for k, v := range formation.Processes {
processes[k] = v
}
if os.Getenv("SINGLETON") == "true" {
processes["mariadb"] = 1
} else {
processes["mariadb"] = 3
}
// Update formation.
logger.Info("updating formation", "app", app, "release_id", release.ID)
formation.Processes = processes
if err := client.PutFormation(formation); err != nil {
logger.Error("put formation error", "app", app, "release_id", release.ID, "err", err)
return err
}
if err := sc.WaitForReadWrite(5 * time.Minute); err != nil {
logger.Error("wait for read write", "err", err)
return errors.New("timed out while starting mariadb cluster")
}
logger.Info("scaling complete")
// Mark as successfully scaled up.
a.scaledUp = true
return nil
}
示例12: TestSlugReleaseGarbageCollection
func (s *CLISuite) TestSlugReleaseGarbageCollection(t *c.C) {
client := s.controllerClient(t)
// create app with gc.max_inactive_slug_releases=3
maxInactiveSlugReleases := 3
app := &ct.App{Meta: map[string]string{"gc.max_inactive_slug_releases": strconv.Itoa(maxInactiveSlugReleases)}}
t.Assert(client.CreateApp(app), c.IsNil)
// create an image artifact
imageArtifact := &ct.Artifact{Type: host.ArtifactTypeDocker, URI: imageURIs["test-apps"]}
t.Assert(client.CreateArtifact(imageArtifact), c.IsNil)
// create 5 slug artifacts
var slug bytes.Buffer
gz := gzip.NewWriter(&slug)
t.Assert(tar.NewWriter(gz).Close(), c.IsNil)
t.Assert(gz.Close(), c.IsNil)
slugs := []string{
"http://blobstore.discoverd/1/slug.tgz",
"http://blobstore.discoverd/2/slug.tgz",
"http://blobstore.discoverd/3/slug.tgz",
"http://blobstore.discoverd/4/slug.tgz",
"http://blobstore.discoverd/5/slug.tgz",
}
slugArtifacts := make([]*ct.Artifact, len(slugs))
for i, uri := range slugs {
req, err := http.NewRequest("PUT", uri, bytes.NewReader(slug.Bytes()))
t.Assert(err, c.IsNil)
res, err := http.DefaultClient.Do(req)
t.Assert(err, c.IsNil)
res.Body.Close()
t.Assert(res.StatusCode, c.Equals, http.StatusOK)
artifact := &ct.Artifact{
Type: host.ArtifactTypeFile,
URI: uri,
Meta: map[string]string{"blobstore": "true"},
}
t.Assert(client.CreateArtifact(artifact), c.IsNil)
slugArtifacts[i] = artifact
}
// create 6 releases, the second being scaled up and having the
// same slug as the third (so prevents the slug being deleted)
releases := make([]*ct.Release, 6)
for i, r := range []struct {
slug *ct.Artifact
active bool
}{
{slugArtifacts[0], false},
{slugArtifacts[1], true},
{slugArtifacts[1], false},
{slugArtifacts[2], false},
{slugArtifacts[3], false},
{slugArtifacts[4], false},
} {
release := &ct.Release{
ArtifactIDs: []string{imageArtifact.ID, r.slug.ID},
Processes: map[string]ct.ProcessType{
"app": {Args: []string{"/bin/pingserv"}, Ports: []ct.Port{{Proto: "tcp"}}},
},
}
t.Assert(client.CreateRelease(release), c.IsNil)
procs := map[string]int{"app": 0}
if r.active {
procs["app"] = 1
}
t.Assert(client.PutFormation(&ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: procs,
}), c.IsNil)
releases[i] = release
}
// scale the last release so we can deploy it
lastRelease := releases[len(releases)-1]
watcher, err := client.WatchJobEvents(app.ID, lastRelease.ID)
t.Assert(err, c.IsNil)
defer watcher.Close()
t.Assert(client.PutFormation(&ct.Formation{
AppID: app.ID,
ReleaseID: lastRelease.ID,
Processes: map[string]int{"app": 1},
}), c.IsNil)
t.Assert(watcher.WaitFor(ct.JobEvents{"app": ct.JobUpEvents(1)}, scaleTimeout, nil), c.IsNil)
t.Assert(client.SetAppRelease(app.ID, lastRelease.ID), c.IsNil)
// subscribe to garbage collection events
gcEvents := make(chan *ct.Event)
stream, err := client.StreamEvents(ct.StreamEventsOptions{
AppID: app.ID,
ObjectTypes: []ct.EventType{ct.EventTypeAppGarbageCollection},
}, gcEvents)
t.Assert(err, c.IsNil)
defer stream.Close()
// deploy a new release with the same slug as the last release
timeoutCh := make(chan struct{})
time.AfterFunc(5*time.Minute, func() { close(timeoutCh) })
newRelease := *lastRelease
//.........這裏部分代碼省略.........
示例13: TestReleaseImages
func (s *ReleaseSuite) TestReleaseImages(t *c.C) {
if testCluster == nil {
t.Skip("cannot boot release cluster")
}
// stream script output to t.Log
logReader, logWriter := io.Pipe()
defer logWriter.Close()
go func() {
buf := bufio.NewReader(logReader)
for {
line, err := buf.ReadString('\n')
if err != nil {
return
}
debug(t, line[0:len(line)-1])
}
}()
// boot the release cluster, release components to a blobstore and output the new version.json
releaseCluster := s.addReleaseHosts(t)
buildHost := releaseCluster.Instances[0]
var versionJSON bytes.Buffer
t.Assert(buildHost.Run("bash -ex", &tc.Streams{Stdin: releaseScript, Stdout: &versionJSON, Stderr: logWriter}), c.IsNil)
var versions map[string]string
t.Assert(json.Unmarshal(versionJSON.Bytes(), &versions), c.IsNil)
// install Flynn from the blobstore on the vanilla host
blobstore := struct{ Blobstore string }{buildHost.IP + ":8080"}
installHost := releaseCluster.Instances[3]
var script bytes.Buffer
installScript.Execute(&script, blobstore)
var installOutput bytes.Buffer
out := io.MultiWriter(logWriter, &installOutput)
t.Assert(installHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)
// check the flynn-host version is correct
var hostVersion bytes.Buffer
t.Assert(installHost.Run("flynn-host version", &tc.Streams{Stdout: &hostVersion}), c.IsNil)
t.Assert(strings.TrimSpace(hostVersion.String()), c.Equals, "v20150131.0-test")
// check rebuilt images were downloaded
for name, id := range versions {
expected := fmt.Sprintf("%s image %s downloaded", name, id)
if !strings.Contains(installOutput.String(), expected) {
t.Fatalf(`expected install to download %s %s`, name, id)
}
}
// installing on an instance with Flynn running should not fail
script.Reset()
installScript.Execute(&script, blobstore)
t.Assert(buildHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: logWriter, Stderr: logWriter}), c.IsNil)
// create a controller client for the release cluster
pin, err := base64.StdEncoding.DecodeString(releaseCluster.ControllerPin)
t.Assert(err, c.IsNil)
client, err := controller.NewClientWithConfig(
"https://"+buildHost.IP,
releaseCluster.ControllerKey,
controller.Config{Pin: pin, Domain: releaseCluster.ControllerDomain},
)
t.Assert(err, c.IsNil)
// deploy a slug based app
slugApp := &ct.App{}
t.Assert(client.CreateApp(slugApp), c.IsNil)
gitreceive, err := client.GetAppRelease("gitreceive")
t.Assert(err, c.IsNil)
imageArtifact := &ct.Artifact{Type: host.ArtifactTypeDocker, URI: gitreceive.Env["SLUGRUNNER_IMAGE_URI"]}
t.Assert(client.CreateArtifact(imageArtifact), c.IsNil)
slugArtifact := &ct.Artifact{Type: host.ArtifactTypeFile, URI: fmt.Sprintf("http://%s:8080/slug.tgz", buildHost.IP)}
t.Assert(client.CreateArtifact(slugArtifact), c.IsNil)
release := &ct.Release{
ArtifactIDs: []string{imageArtifact.ID, slugArtifact.ID},
Processes: map[string]ct.ProcessType{"web": {Cmd: []string{"bin/http"}}},
}
t.Assert(client.CreateRelease(release), c.IsNil)
t.Assert(client.SetAppRelease(slugApp.ID, release.ID), c.IsNil)
watcher, err := client.WatchJobEvents(slugApp.ID, release.ID)
t.Assert(err, c.IsNil)
defer watcher.Close()
t.Assert(client.PutFormation(&ct.Formation{
AppID: slugApp.ID,
ReleaseID: release.ID,
Processes: map[string]int{"web": 1},
}), c.IsNil)
err = watcher.WaitFor(ct.JobEvents{"web": {ct.JobStateUp: 1}}, scaleTimeout, nil)
t.Assert(err, c.IsNil)
// run a cluster update from the blobstore
updateHost := releaseCluster.Instances[1]
script.Reset()
updateScript.Execute(&script, blobstore)
var updateOutput bytes.Buffer
out = io.MultiWriter(logWriter, &updateOutput)
t.Assert(updateHost.Run("bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)
// check rebuilt images were downloaded
for name := range versions {
//.........這裏部分代碼省略.........
示例14: main
//.........這裏部分代碼省略.........
if err := cmd.Run(); err != nil {
log.Fatalln("Build failed:", err)
}
var types []string
if match := typesPattern.FindSubmatch(output.Bytes()); match != nil {
types = strings.Split(string(match[1]), ", ")
}
fmt.Printf("-----> Creating release...\n")
artifact := &ct.Artifact{Type: "docker", URI: os.Getenv("SLUGRUNNER_IMAGE_URI")}
if err := client.CreateArtifact(artifact); err != nil {
log.Fatalln("Error creating artifact:", err)
}
release := &ct.Release{
ArtifactID: artifact.ID,
Env: prevRelease.Env,
Meta: prevRelease.Meta,
}
if release.Meta == nil {
release.Meta = make(map[string]string, len(meta))
}
if release.Env == nil {
release.Env = make(map[string]string, len(env))
}
for k, v := range env {
release.Env[k] = v
}
for k, v := range meta {
release.Meta[k] = v
}
procs := make(map[string]ct.ProcessType)
for _, t := range types {
proc := prevRelease.Processes[t]
proc.Cmd = []string{"start", t}
if t == "web" || strings.HasSuffix(t, "-web") {
proc.Service = app.Name + "-" + t
proc.Ports = []ct.Port{{
Port: 8080,
Proto: "tcp",
Service: &host.Service{
Name: proc.Service,
Create: true,
Check: &host.HealthCheck{Type: "tcp"},
},
}}
}
procs[t] = proc
}
release.Processes = procs
if release.Env == nil {
release.Env = make(map[string]string)
}
release.Env["SLUG_URL"] = slugURL
if err := client.CreateRelease(release); err != nil {
log.Fatalln("Error creating release:", err)
}
if err := client.DeployAppRelease(app.Name, release.ID); err != nil {
log.Fatalln("Error deploying app release:", err)
}
fmt.Println("=====> Application deployed")
if needsDefaultScale(app.ID, prevRelease.ID, procs, client) {
formation := &ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: map[string]int{"web": 1},
}
watcher, err := client.WatchJobEvents(app.ID, release.ID)
if err != nil {
log.Fatalln("Error streaming job events", err)
return
}
defer watcher.Close()
if err := client.PutFormation(formation); err != nil {
log.Fatalln("Error putting formation:", err)
}
fmt.Println("=====> Waiting for web job to start...")
err = watcher.WaitFor(ct.JobEvents{"web": ct.JobUpEvents(1)}, scaleTimeout, func(e *ct.Job) error {
switch e.State {
case ct.JobStateUp:
fmt.Println("=====> Default web formation scaled to 1")
case ct.JobStateDown:
return fmt.Errorf("Failed to scale web process type")
}
return nil
})
if err != nil {
log.Fatalln(err.Error())
}
}
}
示例15: run
//.........這裏部分代碼省略.........
}
procs := make(map[string]ct.ProcessType)
for _, t := range types {
proc := prevRelease.Processes[t]
proc.Args = []string{"/runner/init", "start", t}
if (t == "web" || strings.HasSuffix(t, "-web")) && proc.Service == "" {
proc.Service = app.Name + "-" + t
proc.Ports = []ct.Port{{
Port: 8080,
Proto: "tcp",
Service: &host.Service{
Name: proc.Service,
Create: true,
Check: &host.HealthCheck{Type: "tcp"},
},
}}
}
procs[t] = proc
}
if sb, ok := prevRelease.Processes["slugbuilder"]; ok {
procs["slugbuilder"] = sb
}
release.Processes = procs
if err := client.CreateRelease(release); err != nil {
return fmt.Errorf("Error creating release: %s", err)
}
if err := client.DeployAppRelease(app.Name, release.ID, nil); err != nil {
return fmt.Errorf("Error deploying app release: %s", err)
}
// if the app has a web job and has not been scaled before, create a
// web=1 formation and wait for the "APPNAME-web" service to start
// (whilst also watching job events so the deploy fails if the job
// crashes)
if needsDefaultScale(app.ID, prevRelease.ID, procs, client) {
fmt.Println("=====> Scaling initial release to web=1")
formation := &ct.Formation{
AppID: app.ID,
ReleaseID: release.ID,
Processes: map[string]int{"web": 1},
}
jobEvents := make(chan *ct.Job)
jobStream, err := client.StreamJobEvents(app.ID, jobEvents)
if err != nil {
return fmt.Errorf("Error streaming job events: %s", err)
}
defer jobStream.Close()
serviceEvents := make(chan *discoverd.Event)
serviceStream, err := discoverd.NewService(app.Name + "-web").Watch(serviceEvents)
if err != nil {
return fmt.Errorf("Error streaming service events: %s", err)
}
defer serviceStream.Close()
if err := client.PutFormation(formation); err != nil {
return fmt.Errorf("Error putting formation: %s", err)
}
fmt.Println("-----> Waiting for initial web job to start...")
err = func() error {
for {
select {
case e, ok := <-serviceEvents:
if !ok {
return fmt.Errorf("Service stream closed unexpectedly: %s", serviceStream.Err())
}
if e.Kind == discoverd.EventKindUp && e.Instance.Meta["FLYNN_RELEASE_ID"] == release.ID {
fmt.Println("=====> Initial web job started")
return nil
}
case e, ok := <-jobEvents:
if !ok {
return fmt.Errorf("Job stream closed unexpectedly: %s", jobStream.Err())
}
if e.State == ct.JobStateDown {
return errors.New("Initial web job failed to start")
}
case <-time.After(time.Duration(app.DeployTimeout) * time.Second):
return errors.New("Timed out waiting for initial web job to start")
}
}
}()
if err != nil {
fmt.Println("-----> WARN: scaling initial release down to web=0 due to error")
formation.Processes["web"] = 0
if err := client.PutFormation(formation); err != nil {
// just print this error and return the original error
fmt.Println("-----> WARN: could not scale the initial release down (it may continue to run):", err)
}
return err
}
}
fmt.Println("=====> Application deployed")
return nil
}