func (s *CLISuite) TestExportImport(t *c.C) { srcApp := "app-export" + random.String(8) dstApp := "app-import" + random.String(8) // create and push app+db r := s.newGitRepo(t, "http") t.Assert(r.flynn("create", srcApp), Succeeds) t.Assert(r.flynn("key", "add", r.ssh.Pub), Succeeds) t.Assert(r.git("push", "flynn", "master"), Succeeds) t.Assert(r.flynn("resource", "add", "postgres"), Succeeds) t.Assert(r.flynn("pg", "psql", "--", "-c", "CREATE table foos (data text); INSERT INTO foos (data) VALUES ('foobar')"), Succeeds) // export app file := filepath.Join(t.MkDir(), "export.tar") t.Assert(r.flynn("export", "-f", file), Succeeds) // remove db table from source app t.Assert(r.flynn("pg", "psql", "--", "-c", "DROP TABLE foos"), Succeeds) // import app t.Assert(r.flynn("import", "--name", dstApp, "--file", file), Succeeds) // test db was imported query := r.flynn("-a", dstApp, "pg", "psql", "--", "-c", "SELECT * FROM foos") t.Assert(query, SuccessfulOutputContains, "foobar") // wait for it to start _, err := s.discoverdClient(t).Instances(dstApp+"-web", 10*time.Second) t.Assert(err, c.IsNil) }
func (s *CLISuite) TestExportImport(t *c.C) { srcApp := "app-export" + random.String(8) dstApp := "app-import" + random.String(8) // create app r := s.newGitRepo(t, "http") t.Assert(r.flynn("create", srcApp), Succeeds) // exporting the app without a release should work file := filepath.Join(t.MkDir(), "export.tar") t.Assert(r.flynn("export", "-f", file), Succeeds) assertExportContains := func(paths ...string) { cmd := r.sh(fmt.Sprintf("tar --list --file=%s --strip=1 --show-transformed", file)) t.Assert(cmd, Outputs, strings.Join(paths, "\n")+"\n") } assertExportContains("app.json", "routes.json") // exporting the app with an artifact-less release should work t.Assert(r.flynn("env", "set", "FOO=BAR"), Succeeds) t.Assert(r.flynn("export", "-f", file), Succeeds) assertExportContains("app.json", "routes.json", "release.json") // release the app and provision some dbs t.Assert(r.git("push", "flynn", "master"), Succeeds) t.Assert(r.flynn("resource", "add", "postgres"), Succeeds) t.Assert(r.flynn("pg", "psql", "--", "-c", "CREATE table foos (data text); INSERT INTO foos (data) VALUES ('foobar')"), Succeeds) t.Assert(r.flynn("resource", "add", "mysql"), Succeeds) t.Assert(r.flynn("mysql", "console", "--", "-e", "CREATE TABLE foos (data TEXT); INSERT INTO foos (data) VALUES ('foobar')"), Succeeds) // export app t.Assert(r.flynn("export", "-f", file), Succeeds) assertExportContains( "app.json", "routes.json", "release.json", "artifact.json", "formation.json", "slug.tar.gz", "postgres.dump", "mysql.dump", ) // remove db tables from source app t.Assert(r.flynn("pg", "psql", "--", "-c", "DROP TABLE foos"), Succeeds) t.Assert(r.flynn("mysql", "console", "--", "-e", "DROP TABLE foos"), Succeeds) // remove the git remote t.Assert(r.git("remote", "remove", "flynn"), Succeeds) // import app t.Assert(r.flynn("import", "--name", dstApp, "--file", file), Succeeds) // test dbs were imported query := r.flynn("-a", dstApp, "pg", "psql", "--", "-c", "SELECT * FROM foos") t.Assert(query, SuccessfulOutputContains, "foobar") query = r.flynn("-a", dstApp, "mysql", "console", "--", "-e", "SELECT * FROM foos") t.Assert(query, SuccessfulOutputContains, "foobar") // wait for it to start _, err := s.discoverdClient(t).Instances(dstApp+"-web", 10*time.Second) t.Assert(err, c.IsNil) }
func (s *GitDeploySuite) newGitRepo(t *c.C, nameOrURL string) *gitRepo { dir := filepath.Join(t.MkDir(), "repo") r := &gitRepo{dir, s.ssh, t} if strings.HasPrefix(nameOrURL, "https://") { t.Assert(run(t, exec.Command("git", "clone", nameOrURL, dir)), Succeeds) return r } t.Assert(run(t, exec.Command("cp", "-r", filepath.Join("apps", nameOrURL), dir)), Succeeds) t.Assert(r.git("init"), Succeeds) t.Assert(r.git("add", "."), Succeeds) t.Assert(r.git("commit", "-am", "init"), Succeeds) return r }
func (s *MariaDBSuite) TestDumpRestore(t *c.C) { r := s.newGitRepo(t, "empty") t.Assert(r.flynn("create"), Succeeds) t.Assert(r.flynn("resource", "add", "mysql"), Succeeds) t.Assert(r.flynn("mysql", "console", "--", "-e", "CREATE TABLE T (F text); INSERT INTO T (F) VALUES ('abc')"), Succeeds) file := filepath.Join(t.MkDir(), "db.dump") t.Assert(r.flynn("mysql", "dump", "-f", file), Succeeds) t.Assert(r.flynn("mysql", "console", "--", "-e", "DROP TABLE T"), Succeeds) r.flynn("mysql", "restore", "-f", file) query := r.flynn("mysql", "console", "--", "-e", "SELECT * FROM T") t.Assert(query, SuccessfulOutputContains, "abc") }
func (s *PostgresSuite) TestDumpRestore(t *c.C) { r := s.newGitRepo(t, "empty") t.Assert(r.flynn("create"), Succeeds) t.Assert(r.flynn("resource", "add", "postgres"), Succeeds) t.Assert(r.flynn("pg", "psql", "--", "-c", "CREATE table foos (data text); INSERT INTO foos (data) VALUES ('foobar')"), Succeeds) file := filepath.Join(t.MkDir(), "db.dump") t.Assert(r.flynn("pg", "dump", "-f", file), Succeeds) t.Assert(r.flynn("pg", "psql", "--", "-c", "DROP TABLE foos"), Succeeds) r.flynn("pg", "restore", "-f", file) query := r.flynn("pg", "psql", "--", "-c", "SELECT * FROM foos") t.Assert(query, SuccessfulOutputContains, "foobar") }
func (h *Helper) newGitRepo(t *c.C, nameOrURL string) *gitRepo { dir := filepath.Join(t.MkDir(), "repo") r := &gitRepo{dir, t} if strings.HasPrefix(nameOrURL, "https://") { t.Assert(run(t, exec.Command("git", "clone", nameOrURL, dir)), Succeeds) return r } else if nameOrURL != "" { t.Assert(run(t, exec.Command("cp", "-r", filepath.Join("apps", nameOrURL), dir)), Succeeds) } else { t.Assert(os.Mkdir(dir, 0755), c.IsNil) t.Assert(ioutil.WriteFile(filepath.Join(dir, "file.txt"), []byte("app"), 0644), c.IsNil) } t.Assert(r.git("init"), Succeeds) t.Assert(r.git("add", "."), Succeeds) t.Assert(r.git("commit", "-am", "init"), Succeeds) return r }
func (s *RedisSuite) TestDumpRestore(t *c.C) { a := s.newCliTestApp(t) t.Assert(a.flynn("resource", "add", "redis"), Succeeds) release, err := s.controllerClient(t).GetAppRelease(a.id) t.Assert(err, c.IsNil) t.Assert(release.Env["FLYNN_REDIS"], c.Not(c.Equals), "") a.waitForService(release.Env["FLYNN_REDIS"]) t.Assert(a.flynn("redis", "redis-cli", "set", "foo", "bar"), Succeeds) file := filepath.Join(t.MkDir(), "dump.rdb") t.Assert(a.flynn("redis", "dump", "-f", file), Succeeds) t.Assert(a.flynn("redis", "redis-cli", "del", "foo"), Succeeds) a.flynn("redis", "restore", "-f", file) query := a.flynn("redis", "redis-cli", "get", "foo") t.Assert(query, SuccessfulOutputContains, "bar") }
func (s *CLISuite) TestCreateAppNoGit(t *c.C) { dir := t.MkDir() name := random.String(30) t.Assert(flynn(t, dir, "create", name), Outputs, fmt.Sprintf("Created %s\n", name)) }
func (s *HostSuite) TestUpdate(t *c.C) { dir := t.MkDir() flynnHost := filepath.Join(dir, "flynn-host") run(t, osexec.Command("cp", args.FlynnHost, flynnHost)) // start flynn-host id := random.String(8) var out bytes.Buffer cmd := osexec.Command( flynnHost, "daemon", "--http-port", "11113", "--state", filepath.Join(dir, "host-state.bolt"), "--id", id, "--backend", "mock", "--vol-provider", "mock", "--volpath", filepath.Join(dir, "volumes"), ) cmd.Stdout = &out cmd.Stderr = &out defer func() { debug(t, "*** flynn-host output ***") debug(t, out.String()) debug(t, "*************************") }() t.Assert(cmd.Start(), c.IsNil) defer cmd.Process.Kill() httpClient := &http.Client{Transport: &http.Transport{Dial: dialer.Retry.Dial}} client := cluster.NewHost(id, "http://127.0.0.1:11113", httpClient) // exec a program which exits straight away _, err := client.Update("/bin/true") t.Assert(err, c.NotNil) status, err := client.GetStatus() t.Assert(err, c.IsNil) t.Assert(status.ID, c.Equals, id) t.Assert(status.PID, c.Equals, cmd.Process.Pid) // exec a program which reads the control socket but then exits _, err = client.Update("/bin/bash", "-c", "<&4; exit") t.Assert(err, c.NotNil) status, err = client.GetStatus() t.Assert(err, c.IsNil) t.Assert(status.ID, c.Equals, id) t.Assert(status.PID, c.Equals, cmd.Process.Pid) // exec flynn-host and check we get the status from the new daemon pid, err := client.Update( flynnHost, "daemon", "--http-port", "11113", "--state", filepath.Join(dir, "host-state.bolt"), "--id", id, "--backend", "mock", "--vol-provider", "mock", "--volpath", filepath.Join(dir, "volumes"), ) t.Assert(err, c.IsNil) defer syscall.Kill(pid, syscall.SIGKILL) done := make(chan struct{}) go func() { cmd.Process.Signal(syscall.SIGTERM) syscall.Wait4(cmd.Process.Pid, nil, 0, nil) close(done) }() select { case <-done: case <-time.After(15 * time.Second): t.Fatal("timed out waiting for flynn-host daemon to exit") } // client.GetStatus intermittently returns io.EOF right after the update. We // don't currently understand why (likely due to the way the listener is // passed around), so for now just retry the request. // // TODO(lmars): figure out why and remove this loop. delay := 100 * time.Millisecond for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(delay) { status, err = client.GetStatus() if e, ok := err.(*url.Error); ok && strings.Contains(e.Err.Error(), "EOF") { debugf(t, "got io.EOF from flynn-host, trying again in %s", delay) continue } break } t.Assert(err, c.IsNil) t.Assert(status.ID, c.Equals, id) t.Assert(status.PID, c.Equals, pid) }