phase 2: mattes/migrate -> migratex (#848)

* move mattes migrations to migratex

* changes format of migrations to migratex format
* updates test runner to use new interface (double checked this with printlns,
the tests go fully down and then up, and work on pg/mysql)

* remove mattes/migrate

* update tests from deps

* update readme

* fix other file extensions
This commit is contained in:
Reed Allman
2018-03-13 14:12:34 -07:00
committed by GitHub
parent 1f43545b63
commit 4084b727c0
697 changed files with 16924 additions and 35406 deletions

62
Gopkg.lock generated
View File

@@ -154,7 +154,7 @@
"pkg/term",
"pkg/term/windows"
]
revision = "1346a2c89a11f2d111ff20f46d557f1f9ccbbeb7"
revision = "241c904e6f5fff020890a7641558e83a209c0bbd"
[[projects]]
name = "github.com/docker/go-connections"
@@ -193,8 +193,8 @@
"client/routes",
"models"
]
revision = "847fec724330b2741336431502db292fc5a45211"
version = "0.2.3"
revision = "1c5ec475d4536388b366b1f075945cd64d8c1cb4"
version = "0.2.4"
[[projects]]
name = "github.com/fsouza/go-dockerclient"
@@ -207,8 +207,8 @@
"internal",
"redis"
]
revision = "d1ed5c67e5794de818ea85e6b522fda02623a484"
version = "v1.5.0"
revision = "a69d19351219b6dd56f274f96d85a7014a2ec34e"
version = "v1.6.0"
[[projects]]
name = "github.com/gin-contrib/cors"
@@ -235,8 +235,8 @@
[[projects]]
name = "github.com/go-ini/ini"
packages = ["."]
revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a"
version = "v1.32.0"
revision = "6333e38ac20b8949a8dd68baa3650f4dee8f39f0"
version = "v1.33.0"
[[projects]]
branch = "master"
@@ -287,7 +287,7 @@
branch = "master"
name = "github.com/go-openapi/spec"
packages = ["."]
revision = "1de3e0542de65ad8d75452a595886fdd0befb363"
revision = "d8000b5bfbd1147255710505a27c735b6b2ae2ac"
[[projects]]
branch = "master"
@@ -299,7 +299,7 @@
branch = "master"
name = "github.com/go-openapi/swag"
packages = ["."]
revision = "0d03ad0b6405ada874d59d97c416b5cf4234e154"
revision = "ceb469cb0fdf2d792f28d771bc05da6c606f55e5"
[[projects]]
branch = "master"
@@ -361,7 +361,7 @@
".",
"reflectx"
]
revision = "05cef0741ade10ca668982355b3f3f0bcf0ff0a8"
revision = "cf35089a197953c69420c8d0cecda90809764b1d"
[[projects]]
branch = "master"
@@ -380,17 +380,7 @@
"jlexer",
"jwriter"
]
revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1"
[[projects]]
name = "github.com/mattes/migrate"
packages = [
".",
"database",
"source"
]
revision = "035c07716cd373d88456ec4d701402df52584cb4"
version = "v3.0.1"
revision = "f594efddfa171111dc4349cd6e78e8f61dc7936f"
[[projects]]
name = "github.com/mattn/go-isatty"
@@ -441,7 +431,6 @@
version = "v0.1.1"
[[projects]]
branch = "master"
name = "github.com/openzipkin/zipkin-go"
packages = [
"model",
@@ -449,6 +438,7 @@
"reporter/http"
]
revision = "f197ec29e729f226d23370ea60f0e49b8f44ccf4"
version = "v0.1.0"
[[projects]]
name = "github.com/patrickmn/go-cache"
@@ -491,7 +481,7 @@
"internal/bitbucket.org/ww/goautoneg",
"model"
]
revision = "89604d197083d4781071d3c65855d24ecfb0a563"
revision = "e4aa40a9169a88835b849a6efb71e05dc04b88f0"
[[projects]]
branch = "master"
@@ -502,19 +492,7 @@
"nfs",
"xfs"
]
revision = "75f2d6163c7a100bed6e971044ea3de30ee3a678"
[[projects]]
name = "github.com/rdallman/migrate"
packages = [
".",
"database/mysql",
"database/postgres",
"database/sqlite3",
"source",
"source/go-bindata"
]
revision = "bc72eeb997c7334cb5f05f5aefd2d70bc34d71ef"
revision = "54d17b57dd7d4a3aa092476596b3f8a933bde349"
[[projects]]
name = "github.com/sirupsen/logrus"
@@ -547,13 +525,13 @@
"trace",
"trace/propagation"
]
revision = "4566f1f203a083514e9c57fecc0836ecc4a0eb11"
revision = "f1af72ab88d638dcc20ea6ecf83c98b59b092559"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "8c653846df49742c4c85ec37e5d9f8d3ba657895"
revision = "182114d582623c1caa54f73de9c7224e23a48487"
[[projects]]
branch = "master"
@@ -568,7 +546,7 @@
"lex/httplex",
"trace"
]
revision = "cbe0f9307d0156177f9dd5dc85da1a31abc5f2fb"
revision = "ae89d30ce0c63142b652837da33d782e2b0a9b25"
[[projects]]
branch = "master"
@@ -577,7 +555,7 @@
"unix",
"windows"
]
revision = "f6cff0780e542efa0c8e864dc8fa522808f6a598"
revision = "c28acc882ebcbfbe8ce9f0f14b9ac26ee138dd51"
[[projects]]
name = "golang.org/x/text"
@@ -605,7 +583,7 @@
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "2b5a72b8730b0b16380010cfe5286c42108d88e7"
revision = "df60624c1e9b9d2973e889c7a1cff73155da81c4"
[[projects]]
name = "google.golang.org/grpc"
@@ -661,6 +639,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "1818456581749a8ec46a6fded1c10e7f706f9e77aa1ac2061d25c3080883376d"
inputs-digest = "4001fea69927fe605d8c5a47d02f119a0eef15b291eff46d6d993309462f5406"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -53,10 +53,6 @@ ignored = ["github.com/fnproject/fn/cli"]
name = "github.com/docker/distribution"
revision = "bc3c7b0525e59d3ecfab3e1568350895fd4a462f"
[[constraint]]
name = "github.com/rdallman/migrate" # TODO change to mattes/migrate w/ https://github.com/mattes/migrate/pull/299
revision = "bc72eeb997c7334cb5f05f5aefd2d70bc34d71ef"
[[constraint]]
# NOTE: locked for a reason - https://github.com/go-sql-driver/mysql/issues/657
name = "github.com/go-sql-driver/mysql"

View File

@@ -22,7 +22,6 @@ var (
ErrLocked = errors.New("database is locked")
ErrDirty = errors.New("database is dirty")
ErrOutOfOrder = errors.New("non-contiguous migration attempted")
)
const (
@@ -30,8 +29,8 @@ const (
)
type Migration interface {
Up(*sqlx.Tx) error
Down(*sqlx.Tx) error
Up(context.Context, *sqlx.Tx) error
Down(context.Context, *sqlx.Tx) error
Version() int64
}
@@ -45,13 +44,13 @@ var _ Migration = new(MigFields)
// MigFields implements Migration and can be used for convenience.
type MigFields struct {
UpFunc func(*sqlx.Tx) error
DownFunc func(*sqlx.Tx) error
UpFunc func(context.Context, *sqlx.Tx) error
DownFunc func(context.Context, *sqlx.Tx) error
VersionFunc func() int64
}
func (m MigFields) Up(tx *sqlx.Tx) error { return m.UpFunc(tx) }
func (m MigFields) Down(tx *sqlx.Tx) error { return m.DownFunc(tx) }
func (m MigFields) Up(ctx context.Context, tx *sqlx.Tx) error { return m.UpFunc(ctx, tx) }
func (m MigFields) Down(ctx context.Context, tx *sqlx.Tx) error { return m.DownFunc(ctx, tx) }
func (m MigFields) Version() int64 { return m.VersionFunc() }
// TODO instance must have `multiStatements` set to true ?
@@ -65,13 +64,10 @@ func Down(ctx context.Context, db *sqlx.DB, migs []Migration) error {
}
func migrate(ctx context.Context, db *sqlx.DB, migs []Migration, up bool) error {
var curVersion int64
var curVersion int64 // could be NilVersion, is ok
err := tx(ctx, db, func(tx *sqlx.Tx) error {
err := ensureVersionTable(ctx, tx)
if err != nil {
return err
}
var dirty bool
var err error
curVersion, dirty, err = Version(ctx, tx)
if dirty {
return ErrDirty
@@ -90,11 +86,11 @@ func migrate(ctx context.Context, db *sqlx.DB, migs []Migration, up bool) error
if up {
sort.Sort(sorted(migs))
} else {
migs = []Migration(sort.Reverse(sorted(migs)).(sorted))
sort.Sort(sort.Reverse(sorted(migs)))
}
for _, m := range migs {
// skip over migrations we have run
if (up && curVersion < m.Version()) || (!up && curVersion > m.Version()) {
if (up && curVersion < m.Version()) || (!up && curVersion >= m.Version()) {
// do each individually, for large migrations it's better to checkpoint
// than to try to do them all in one big go.
@@ -182,9 +178,9 @@ func run(ctx context.Context, db *sqlx.DB, m Migration, up bool) error {
// enforce monotonicity
if up && curVersion != NilVersion && m.Version() != curVersion+1 {
return ErrOutOfOrder
return fmt.Errorf("non-contiguous migration attempted up: %v != %v", m.Version(), curVersion+1)
} else if !up && m.Version() != curVersion { // down is always unraveling
return ErrOutOfOrder
return fmt.Errorf("non-contiguous migration attempted down: %v != %v", m.Version(), curVersion)
}
// TODO is this robust enough? we could check
@@ -194,12 +190,12 @@ func run(ctx context.Context, db *sqlx.DB, m Migration, up bool) error {
}
// TODO we don't need the dirty bit anymore since we're using transactions?
err = SetVersion(ctx, tx, m.Version(), true)
err = SetVersion(ctx, tx, version, true)
if up {
err = m.Up(tx)
err = m.Up(ctx, tx)
} else {
err = m.Down(tx)
err = m.Down(ctx, tx)
}
if err != nil {
@@ -230,7 +226,7 @@ func lock(ctx context.Context, tx *sqlx.Tx) error {
var query string
switch tx.DriverName() {
case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres":
query = `SELECT pg_try_advisory_lock($1)`
query = `SELECT pg_try_advisory_lock(?)`
case "mysql", "oci8", "ora", "goracle":
query = "SELECT GET_LOCK(?, -1)"
case "sqlite3":
@@ -260,7 +256,7 @@ func unlock(ctx context.Context, tx *sqlx.Tx) error {
var query string
switch tx.DriverName() {
case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres":
query = `SELECT pg_advisory_unlock($1)`
query = `SELECT pg_advisory_unlock(?)`
case "mysql", "oci8", "ora", "goracle":
query = `SELECT RELEASE_LOCK(?)`
case "sqlite3":
@@ -277,6 +273,11 @@ func unlock(ctx context.Context, tx *sqlx.Tx) error {
}
func SetVersion(ctx context.Context, tx *sqlx.Tx, version int64, dirty bool) error {
err := ensureVersionTable(ctx, tx)
if err != nil {
return nil
}
// TODO need to handle down migration better
// ideally, we have a record of each up/down migration with a timestamp for auditing,
// this just nukes the whole table which is kinda lame.
@@ -286,7 +287,7 @@ func SetVersion(ctx context.Context, tx *sqlx.Tx, version int64, dirty bool) err
}
if version >= 0 {
query = tx.Rebind("INSERT INTO `" + MigrationsTable + "` (version, dirty) VALUES (?, ?)")
query = tx.Rebind(`INSERT INTO ` + MigrationsTable + ` (version, dirty) VALUES (?, ?)`)
if _, err := tx.ExecContext(ctx, query, version, dirty); err != nil {
return err
}
@@ -296,7 +297,7 @@ func SetVersion(ctx context.Context, tx *sqlx.Tx, version int64, dirty bool) err
}
func Version(ctx context.Context, tx *sqlx.Tx) (version int64, dirty bool, err error) {
query := tx.Rebind("SELECT version, dirty FROM `" + MigrationsTable + "` LIMIT 1")
query := tx.Rebind(`SELECT version, dirty FROM ` + MigrationsTable + ` LIMIT 1`)
err = tx.QueryRowContext(ctx, query).Scan(&version, &dirty)
switch {
case err == sql.ErrNoRows:

View File

@@ -14,15 +14,15 @@ const testsqlite3 = "file::memory:?mode=memory&cache=shared"
type tm struct{}
func (t *tm) Up(tx *sqlx.Tx) error {
_, err := tx.Exec(`CREATE TABLE IF NOT EXISTS foo (
func (t *tm) Up(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS foo (
bar bigint NOT NULL PRIMARY KEY
)`)
return err
}
func (t *tm) Down(tx *sqlx.Tx) error {
_, err := tx.Exec("DROP TABLE foo")
func (t *tm) Down(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "DROP TABLE foo")
return err
}

View File

@@ -1 +0,0 @@
ALTER TABLE routes DROP COLUMN created_at;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up1(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes ADD created_at text;")
return err
}
func down1(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes DROP COLUMN created_at;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(1),
UpFunc: up1,
DownFunc: down1,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE routes ADD created_at text;

View File

@@ -1 +0,0 @@
ALTER TABLE calls DROP COLUMN stats;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up2(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE calls ADD stats text;")
return err
}
func down2(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE calls DROP COLUMN stats;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(2),
UpFunc: up2,
DownFunc: down2,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE calls ADD stats text;

View File

@@ -1 +0,0 @@
ALTER TABLE calls DROP COLUMN error;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up3(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE calls ADD error text;")
return err
}
func down3(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE calls DROP COLUMN error;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(3),
UpFunc: up3,
DownFunc: down3,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE calls ADD error text;

View File

@@ -1 +0,0 @@
ALTER TABLE routes DROP COLUMN updated_at;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up4(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes ADD updated_at VARCHAR(256);")
return err
}
func down4(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes DROP COLUMN updated_at;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(4),
UpFunc: up4,
DownFunc: down4,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE routes ADD updated_at varchar(256);

View File

@@ -1 +0,0 @@
ALTER TABLE apps DROP COLUMN created_at;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up5(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE apps ADD created_at VARCHAR(256);")
return err
}
func down5(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE apps DROP COLUMN created_at;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(5),
UpFunc: up5,
DownFunc: down5,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE apps ADD created_at varchar(256);

View File

@@ -1 +0,0 @@
ALTER TABLE apps DROP COLUMN updated_at;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up6(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE apps ADD updated_at VARCHAR(256);")
return err
}
func down6(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE apps DROP COLUMN updated_at;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(6),
UpFunc: up6,
DownFunc: down6,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE apps ADD updated_at varchar(256);

View File

@@ -1 +0,0 @@
ALTER TABLE routes DROP COLUMN cpus;

View File

@@ -0,0 +1,26 @@
package migrations
import (
"context"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up7(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes ADD cpus int;")
return err
}
func down7(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes DROP COLUMN cpus;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(7),
UpFunc: up7,
DownFunc: down7,
})
}

View File

@@ -1 +0,0 @@
ALTER TABLE routes ADD cpus int;

View File

@@ -2,39 +2,49 @@
All migration files should be of the format:
`[0-9]+_[add|remove]_model[_field]*.[up|down].sql`
`[0-9]+_[add|remove]_model[_field]*.go`
The number at the beginning of the file name should be monotonically
increasing, from the last highest file number in this directory. E.g. if there
is `11_add_foo_bar.up.sql`, your new file should be `12_add_bar_baz.up.sql`.
is `11_add_foo_bar.go`, your new file should be `12_add_bar_baz.go`.
All `*.up.sql` files must have an accompanying `*.down.sql` file in order to
pass review.
Each migration file have to contain both up and down function:
The contents of each file should contain only 1 ANSI sql query. For help, you
may refer to https://github.com/mattes/migrate/blob/master/MIGRATIONS.md which
illustrates some of the finer points.
```go
package migrations
After creating the file you will need to run, in the same directory as this
README:
import (
"context"
```sh
$ go generate
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/jmoiron/sqlx"
)
func up1(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes ADD created_at text;")
return err
}
func down1(ctx context.Context, tx *sqlx.Tx) error {
_, err := tx.ExecContext(ctx, "ALTER TABLE routes DROP COLUMN created_at;")
return err
}
func init() {
Migrations = append(Migrations, &migratex.MigFields{
VersionFunc: vfunc(1),
UpFunc: up1,
DownFunc: down1,
})
}
```
NOTE: You may need to `go get -u github.com/jteeuwen/go-bindata/...` before running `go
generate` in order for it to work.
Each migration must initialize a `migratex.Migration` with corresponding
version and up/down function.
After running `go generate`, the `migrations.go` file should be updated. Check
the updated version of this as well as the new `.sql` file into git.
We have elected to expose fn's specific sql migrations as an exported global
list `migrations.Migrations` from this package, you must simply add your
migration and append it to this list.
After adding the migration, be sure to update the fields in the sql tables in
`sql.go` up one package. For example, if you added a column `foo` to `routes`,
add this field to the routes `CREATE TABLE` query, as well as any queries
where it should be returned.
After doing this, run the test suite to make sure the sql queries work as
intended and voila. The test suite will ensure that the up and down migrations
work as well as a fresh db. The down migrations will not be tested against
SQLite3 as it does not support `ALTER TABLE DROP COLUMN`, but will still be
tested against postgres and MySQL.
Please note that every database change should be considered as 1 individual
migration (new table, new column, column type change, etc.)

View File

@@ -1,12 +0,0 @@
package migrations
//go:generate go-bindata -ignore README.md -ignore migrations.go -ignore index.go -o migrations.go -pkg migrations .
// migrations are generated from this cwd with go generate.
// install https://github.com/jteeuwen/go-bindata for go generate
// command to work properly.
// this will generate a go file with go-bindata of all the migration
// files in 1 go file, so that migrations can be run remotely without
// having to carry the migration files around (i.e. since they are
// compiled into the go binary)

View File

@@ -1,534 +0,0 @@
// Code generated by go-bindata.
// sources:
// 1_add_route_created_at.down.sql
// 1_add_route_created_at.up.sql
// 2_add_call_stats.down.sql
// 2_add_call_stats.up.sql
// 3_add_call_error.down.sql
// 3_add_call_error.up.sql
// 4_add_route_updated_at.down.sql
// 4_add_route_updated_at.up.sql
// 5_add_app_created_at.down.sql
// 5_add_app_created_at.up.sql
// 6_add_app_updated_at.down.sql
// 6_add_app_updated_at.up.sql
// 7_add_route_cpus.down.sql
// 7_add_route_cpus.up.sql
// DO NOT EDIT!
package migrations
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
}
type asset struct {
bytes []byte
info os.FileInfo
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func (fi bindataFileInfo) Name() string {
return fi.name
}
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
return false
}
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var __1_add_route_created_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2e\x4a\x4d\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\x47\xfd\x3b\xbe\x2b\x00\x00\x00")
func _1_add_route_created_atDownSqlBytes() ([]byte, error) {
return bindataRead(
__1_add_route_created_atDownSql,
"1_add_route_created_at.down.sql",
)
}
func _1_add_route_created_atDownSql() (*asset, error) {
bytes, err := _1_add_route_created_atDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1_add_route_created_at.down.sql", size: 43, mode: os.FileMode(420), modTime: time.Unix(1510963763, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __1_add_route_created_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x74\x71\x51\x48\x2e\x4a\x4d\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x49\xad\x28\xb1\xe6\x02\x04\x00\x00\xff\xff\x3b\x59\x9c\x54\x28\x00\x00\x00")
func _1_add_route_created_atUpSqlBytes() ([]byte, error) {
return bindataRead(
__1_add_route_created_atUpSql,
"1_add_route_created_at.up.sql",
)
}
func _1_add_route_created_atUpSql() (*asset, error) {
bytes, err := _1_add_route_created_atUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1_add_route_created_at.up.sql", size: 40, mode: os.FileMode(420), modTime: time.Unix(1510963763, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __2_add_call_statsDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4e\xcc\xc9\x29\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x2e\x49\x2c\x29\xb6\xe6\x02\x04\x00\x00\xff\xff\xd3\x09\xeb\x22\x25\x00\x00\x00")
func _2_add_call_statsDownSqlBytes() ([]byte, error) {
return bindataRead(
__2_add_call_statsDownSql,
"2_add_call_stats.down.sql",
)
}
func _2_add_call_statsDownSql() (*asset, error) {
bytes, err := _2_add_call_statsDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "2_add_call_stats.down.sql", size: 37, mode: os.FileMode(420), modTime: time.Unix(1511917353, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __2_add_call_statsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4e\xcc\xc9\x29\x56\x70\x74\x71\x51\x28\x2e\x49\x2c\x29\x56\x28\x49\xad\x28\xb1\xe6\x02\x04\x00\x00\xff\xff\x29\xde\x11\xe8\x22\x00\x00\x00")
func _2_add_call_statsUpSqlBytes() ([]byte, error) {
return bindataRead(
__2_add_call_statsUpSql,
"2_add_call_stats.up.sql",
)
}
func _2_add_call_statsUpSql() (*asset, error) {
bytes, err := _2_add_call_statsUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "2_add_call_stats.up.sql", size: 34, mode: os.FileMode(420), modTime: time.Unix(1511917353, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __3_add_call_errorDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4e\xcc\xc9\x29\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2d\x2a\xca\x2f\xb2\xe6\x02\x04\x00\x00\xff\xff\xc1\x14\x26\x51\x25\x00\x00\x00")
func _3_add_call_errorDownSqlBytes() ([]byte, error) {
return bindataRead(
__3_add_call_errorDownSql,
"3_add_call_error.down.sql",
)
}
func _3_add_call_errorDownSql() (*asset, error) {
bytes, err := _3_add_call_errorDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "3_add_call_error.down.sql", size: 37, mode: os.FileMode(420), modTime: time.Unix(1511989827, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __3_add_call_errorUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4e\xcc\xc9\x29\x56\x70\x74\x71\x51\x48\x2d\x2a\xca\x2f\x52\x28\x49\xad\x28\xb1\xe6\x02\x04\x00\x00\xff\xff\xaf\xba\x27\xcd\x22\x00\x00\x00")
func _3_add_call_errorUpSqlBytes() ([]byte, error) {
return bindataRead(
__3_add_call_errorUpSql,
"3_add_call_error.up.sql",
)
}
func _3_add_call_errorUpSql() (*asset, error) {
bytes, err := _3_add_call_errorUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "3_add_call_error.up.sql", size: 34, mode: os.FileMode(420), modTime: time.Unix(1511989827, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __4_add_route_updated_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\xa4\x67\xb0\xea\x2b\x00\x00\x00")
func _4_add_route_updated_atDownSqlBytes() ([]byte, error) {
return bindataRead(
__4_add_route_updated_atDownSql,
"4_add_route_updated_at.down.sql",
)
}
func _4_add_route_updated_atDownSql() (*asset, error) {
bytes, err := _4_add_route_updated_atDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "4_add_route_updated_at.down.sql", size: 43, mode: os.FileMode(420), modTime: time.Unix(1514060619, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __4_add_route_updated_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x74\x71\x51\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x4b\x2c\x4a\xce\x48\x2c\xd2\x30\x32\x35\xd3\xb4\xe6\x02\x04\x00\x00\xff\xff\x54\xf7\xac\x11\x30\x00\x00\x00")
func _4_add_route_updated_atUpSqlBytes() ([]byte, error) {
return bindataRead(
__4_add_route_updated_atUpSql,
"4_add_route_updated_at.up.sql",
)
}
func _4_add_route_updated_atUpSql() (*asset, error) {
bytes, err := _4_add_route_updated_atUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "4_add_route_updated_at.up.sql", size: 48, mode: os.FileMode(420), modTime: time.Unix(1514060619, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __5_add_app_created_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2e\x4a\x4d\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\xd2\xde\x5c\x98\x29\x00\x00\x00")
func _5_add_app_created_atDownSqlBytes() ([]byte, error) {
return bindataRead(
__5_add_app_created_atDownSql,
"5_add_app_created_at.down.sql",
)
}
func _5_add_app_created_atDownSql() (*asset, error) {
bytes, err := _5_add_app_created_atDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "5_add_app_created_at.down.sql", size: 41, mode: os.FileMode(420), modTime: time.Unix(1514060619, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __5_add_app_created_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x74\x71\x51\x48\x2e\x4a\x4d\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x4b\x2c\x4a\xce\x48\x2c\xd2\x30\x32\x35\xd3\xb4\xe6\x02\x04\x00\x00\xff\xff\x76\x6c\x0f\x45\x2e\x00\x00\x00")
func _5_add_app_created_atUpSqlBytes() ([]byte, error) {
return bindataRead(
__5_add_app_created_atUpSql,
"5_add_app_created_at.up.sql",
)
}
func _5_add_app_created_atUpSql() (*asset, error) {
bytes, err := _5_add_app_created_atUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "5_add_app_created_at.up.sql", size: 46, mode: os.FileMode(420), modTime: time.Unix(1514060619, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __6_add_app_updated_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\x31\x44\xd7\xcc\x29\x00\x00\x00")
func _6_add_app_updated_atDownSqlBytes() ([]byte, error) {
return bindataRead(
__6_add_app_updated_atDownSql,
"6_add_app_updated_at.down.sql",
)
}
func _6_add_app_updated_atDownSql() (*asset, error) {
bytes, err := _6_add_app_updated_atDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "6_add_app_updated_at.down.sql", size: 41, mode: os.FileMode(420), modTime: time.Unix(1514060619, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __6_add_app_updated_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x74\x71\x51\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x4b\x2c\x4a\xce\x48\x2c\xd2\x30\x32\x35\xd3\xb4\xe6\x02\x04\x00\x00\xff\xff\x65\x01\x8b\x34\x2e\x00\x00\x00")
func _6_add_app_updated_atUpSqlBytes() ([]byte, error) {
return bindataRead(
__6_add_app_updated_atUpSql,
"6_add_app_updated_at.up.sql",
)
}
func _6_add_app_updated_atUpSql() (*asset, error) {
bytes, err := _6_add_app_updated_atUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "6_add_app_updated_at.up.sql", size: 46, mode: os.FileMode(420), modTime: time.Unix(1514060619, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __7_add_route_cpusDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2e\x28\x2d\xb6\xe6\x02\x04\x00\x00\xff\xff\xec\x60\x24\xd0\x25\x00\x00\x00")
func _7_add_route_cpusDownSqlBytes() ([]byte, error) {
return bindataRead(
__7_add_route_cpusDownSql,
"7_add_route_cpus.down.sql",
)
}
func _7_add_route_cpusDownSql() (*asset, error) {
bytes, err := _7_add_route_cpusDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "7_add_route_cpus.down.sql", size: 37, mode: os.FileMode(420), modTime: time.Unix(1515624756, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var __7_add_route_cpusUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x74\x71\x51\x48\x2e\x28\x2d\x56\xc8\xcc\x2b\xb1\xe6\x02\x04\x00\x00\xff\xff\xf1\x18\xf8\xa9\x21\x00\x00\x00")
func _7_add_route_cpusUpSqlBytes() ([]byte, error) {
return bindataRead(
__7_add_route_cpusUpSql,
"7_add_route_cpus.up.sql",
)
}
func _7_add_route_cpusUpSql() (*asset, error) {
bytes, err := _7_add_route_cpusUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "7_add_route_cpus.up.sql", size: 33, mode: os.FileMode(420), modTime: time.Unix(1515628068, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"1_add_route_created_at.down.sql": _1_add_route_created_atDownSql,
"1_add_route_created_at.up.sql": _1_add_route_created_atUpSql,
"2_add_call_stats.down.sql": _2_add_call_statsDownSql,
"2_add_call_stats.up.sql": _2_add_call_statsUpSql,
"3_add_call_error.down.sql": _3_add_call_errorDownSql,
"3_add_call_error.up.sql": _3_add_call_errorUpSql,
"4_add_route_updated_at.down.sql": _4_add_route_updated_atDownSql,
"4_add_route_updated_at.up.sql": _4_add_route_updated_atUpSql,
"5_add_app_created_at.down.sql": _5_add_app_created_atDownSql,
"5_add_app_created_at.up.sql": _5_add_app_created_atUpSql,
"6_add_app_updated_at.down.sql": _6_add_app_updated_atDownSql,
"6_add_app_updated_at.up.sql": _6_add_app_updated_atUpSql,
"7_add_route_cpus.down.sql": _7_add_route_cpusDownSql,
"7_add_route_cpus.up.sql": _7_add_route_cpusUpSql,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
cannonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"1_add_route_created_at.down.sql": &bintree{_1_add_route_created_atDownSql, map[string]*bintree{}},
"1_add_route_created_at.up.sql": &bintree{_1_add_route_created_atUpSql, map[string]*bintree{}},
"2_add_call_stats.down.sql": &bintree{_2_add_call_statsDownSql, map[string]*bintree{}},
"2_add_call_stats.up.sql": &bintree{_2_add_call_statsUpSql, map[string]*bintree{}},
"3_add_call_error.down.sql": &bintree{_3_add_call_errorDownSql, map[string]*bintree{}},
"3_add_call_error.up.sql": &bintree{_3_add_call_errorUpSql, map[string]*bintree{}},
"4_add_route_updated_at.down.sql": &bintree{_4_add_route_updated_atDownSql, map[string]*bintree{}},
"4_add_route_updated_at.up.sql": &bintree{_4_add_route_updated_atUpSql, map[string]*bintree{}},
"5_add_app_created_at.down.sql": &bintree{_5_add_app_created_atDownSql, map[string]*bintree{}},
"5_add_app_created_at.up.sql": &bintree{_5_add_app_created_atUpSql, map[string]*bintree{}},
"6_add_app_updated_at.down.sql": &bintree{_6_add_app_updated_atDownSql, map[string]*bintree{}},
"6_add_app_updated_at.up.sql": &bintree{_6_add_app_updated_atUpSql, map[string]*bintree{}},
"7_add_route_cpus.down.sql": &bintree{_7_add_route_cpusDownSql, map[string]*bintree{}},
"7_add_route_cpus.up.sql": &bintree{_7_add_route_cpusUpSql, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil {
return err
}
return nil
}
// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

View File

@@ -0,0 +1,10 @@
package migrations
import (
"github.com/fnproject/fn/api/datastore/sql/migratex"
)
// Migrations is the list of fn specific sql migrations to run
var Migrations []migratex.Migration
func vfunc(v int64) func() int64 { return func() int64 { return v } }

View File

@@ -14,6 +14,7 @@ import (
"time"
"github.com/fnproject/fn/api/common"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/fnproject/fn/api/datastore/sql/migrations"
"github.com/fnproject/fn/api/models"
"github.com/go-sql-driver/mysql"
@@ -23,12 +24,6 @@ import (
_ "github.com/lib/pq"
"github.com/mattn/go-sqlite3"
_ "github.com/mattn/go-sqlite3"
"github.com/rdallman/migrate"
_ "github.com/rdallman/migrate/database/mysql"
_ "github.com/rdallman/migrate/database/postgres"
_ "github.com/rdallman/migrate/database/sqlite3"
"github.com/rdallman/migrate/source"
"github.com/rdallman/migrate/source/go-bindata"
"github.com/sirupsen/logrus"
)
@@ -147,7 +142,9 @@ func newDS(ctx context.Context, url *url.URL) (*sqlStore, error) {
db.SetMaxIdleConns(maxIdleConns)
log.WithFields(logrus.Fields{"max_idle_connections": maxIdleConns, "datastore": driver}).Info("datastore dialed")
err = runMigrations(url.String(), checkExistence(db)) // original url string
sdb := &sqlStore{db: db}
err = sdb.runMigrations(ctx, checkExistence(db), migrations.Migrations)
if err != nil {
log.WithError(err).Error("error running migrations")
return nil, err
@@ -164,7 +161,7 @@ func newDS(ctx context.Context, url *url.URL) (*sqlStore, error) {
}
}
return &sqlStore{db: db}, nil
return sdb, nil
}
func pingWithRetry(ctx context.Context, attempts int, sleep time.Duration, db *sqlx.DB) (err error) {
@@ -201,52 +198,29 @@ func checkExistence(db *sqlx.DB) bool {
// check if the db already existed, if the db is brand new then we can skip
// over all the migrations BUT we must be sure to set the right migration
// number so that only current migrations are skipped, not any future ones.
func runMigrations(url string, exists bool) error {
m, err := migrator(url)
if err != nil {
return err
}
defer m.Close()
if !exists {
func (ds *sqlStore) runMigrations(ctx context.Context, dbExists bool, migrations []migratex.Migration) error {
if !dbExists {
// set to highest and bail
return m.Force(latestVersion(migrations.AssetNames()))
return ds.Tx(func(tx *sqlx.Tx) error {
return migratex.SetVersion(ctx, tx, latestVersion(migrations), false)
})
}
// run any migrations needed to get to latest, if any
err = m.Up()
if err == migrate.ErrNoChange { // we don't care, but want other errors
err = nil
}
return err
}
func migrator(url string) (*migrate.Migrate, error) {
s := bindata.Resource(migrations.AssetNames(),
func(name string) ([]byte, error) {
return migrations.Asset(name)
})
d, err := bindata.WithInstance(s)
if err != nil {
return nil, err
}
return migrate.NewWithSourceInstance("go-bindata", d, url)
return migratex.Up(ctx, ds.db, migrations)
}
// latest version will find the latest version from a list of migration
// names (not from the db)
func latestVersion(migs []string) int {
var highest uint
for _, m := range migs {
mig, _ := source.Parse(m)
if mig.Version > highest {
highest = mig.Version
func latestVersion(migs []migratex.Migration) int64 {
var highest int64
for _, mig := range migs {
if mig.Version() > highest {
highest = mig.Version()
}
}
return int(highest)
return highest
}
// clear is for tests only, be careful, it deletes all records.

View File

@@ -1,14 +1,15 @@
package sql
import (
"context"
"net/url"
"os"
"testing"
"context"
"github.com/fnproject/fn/api/datastore/internal/datastoretest"
"github.com/fnproject/fn/api/datastore/internal/datastoreutil"
"github.com/fnproject/fn/api/datastore/sql/migratex"
"github.com/fnproject/fn/api/datastore/sql/migrations"
"github.com/fnproject/fn/api/models"
)
@@ -23,12 +24,7 @@ func newWithMigrations(ctx context.Context, url *url.URL) (*sqlStore, error) {
return nil, err
}
m, err := migrator(url.String())
if err != nil {
return nil, err
}
err = m.Down()
err = migratex.Down(ctx, ds.db, migrations.Migrations)
if err != nil {
return nil, err
}

View File

@@ -360,9 +360,10 @@ func TestOversizedLog(t *testing.T) {
if err != nil {
t.Error(err.Error())
} else {
if len(logObj.Payload) >= size {
log := logObj.Payload.Log.Log
if len(log) >= size {
t.Errorf("Log entry suppose to be truncated up to expected size %v, got %v",
size/1024, len(logObj.Payload))
size/1024, len(log))
}
}
DeleteApp(t, s.Context, s.Client, s.AppName)

View File

@@ -32,28 +32,21 @@
# the case. Therefore, you don't have to disable it anymore.
#
FROM buildpack-deps:stretch AS base
FROM golang:1.9.4 AS base
# FIXME(vdemeester) this is kept for other script depending on it to not fail right away
# Remove this once the other scripts uses something else to detect the version
ENV GO_VERSION 1.9.4
# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
FROM base AS golang
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# with a heads-up.
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.9.4
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
| tar -xzC /usr/local
ENV PATH=/usr/local/go/bin:/go/bin:$PATH GOPATH=/go
FROM base AS criu
# Install CRIU for checkpoint/restore support
ENV CRIU_VERSION 3.6
# Install dependancy packages specific to criu
RUN apt-get update && apt-get install -y \
RUN case $(uname -m) in \
x86_64) \
apt-get update && apt-get install -y \
libnet-dev \
libprotobuf-c0-dev \
libprotobuf-dev \
@@ -66,10 +59,15 @@ RUN apt-get update && apt-get install -y \
&& curl -sSL https://github.com/checkpoint-restore/criu/archive/v${CRIU_VERSION}.tar.gz | tar -C /usr/src/criu/ -xz --strip-components=1 \
&& cd /usr/src/criu \
&& make \
&& make PREFIX=/opt/criu install-criu
&& make PREFIX=/opt/criu install-criu ;\
;; \
armv7l|aarch64|ppc64le|s390x) \
mkdir -p /opt/criu; \
;; \
esac
FROM golang AS registry
FROM base AS registry
# Install two versions of the registry. The first is an older version that
# only supports schema1 manifests. The second is a newer version that supports
# both. This allows integration-cli tests to cover push/pull with both schema1
@@ -82,14 +80,18 @@ RUN set -x \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
&& case $(uname -m) in \
x86_64|ppc64le|s390x) \
(cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1"); \
GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"; \
go build -buildmode=pie -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry; \
;; \
esac \
&& rm -rf "$GOPATH"
FROM golang AS notary
FROM base AS notary
# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
@@ -113,7 +115,7 @@ RUN git clone https://github.com/docker/docker-py.git /docker-py \
FROM golang AS swagger
FROM base AS swagger
# Install go-swagger for validating swagger.yaml
ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb
RUN set -x \
@@ -124,56 +126,57 @@ RUN set -x \
&& rm -rf "$GOPATH"
FROM golang AS frozen-images
FROM base AS frozen-images
RUN apt-get update && apt-get install -y jq ca-certificates --no-install-recommends
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
COPY contrib/download-frozen-image-v2.sh /
RUN /download-frozen-image-v2.sh /docker-frozen-images \
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
busybox:1.27-glibc@sha256:8c8f261a462eead45ab8e610d3e8f7a1e4fd1cd9bed5bc0a0c386784ab105d8e \
busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0 \
busybox:glibc@sha256:0b55a30394294ab23b9afd58fab94e61a923f5834fba7ddbae7f8e0c11ba85e6 \
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
# See also ensureFrozenImagesLinux() in "integration-cli/fixtures_linux_daemon_test.go" (which needs to be updated when adding images to this list)
# Just a little hack so we don't have to install these deps twice, once for runc and once for dockerd
FROM golang AS runtime-dev
FROM base AS runtime-dev
RUN apt-get update && apt-get install -y \
libapparmor-dev \
libseccomp-dev
FROM golang AS tomlv
FROM base AS tomlv
ENV INSTALL_BINARY_NAME=tomlv
COPY hack/dockerfile/install/install.sh ./install.sh
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
RUN PREFIX=/opt/$INSTALL_BINARY_NAME ./install.sh $INSTALL_BINARY_NAME
FROM golang AS vndr
FROM base AS vndr
ENV INSTALL_BINARY_NAME=vndr
COPY hack/dockerfile/install/install.sh ./install.sh
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
RUN PREFIX=/opt/$INSTALL_BINARY_NAME ./install.sh $INSTALL_BINARY_NAME
FROM golang AS containerd
FROM base AS containerd
RUN apt-get update && apt-get install -y btrfs-tools
ENV INSTALL_BINARY_NAME=containerd
COPY hack/dockerfile/install/install.sh ./install.sh
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
RUN PREFIX=/opt/$INSTALL_BINARY_NAME ./install.sh $INSTALL_BINARY_NAME
FROM golang AS proxy
FROM base AS proxy
ENV INSTALL_BINARY_NAME=proxy
COPY hack/dockerfile/install/install.sh ./install.sh
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
RUN PREFIX=/opt/$INSTALL_BINARY_NAME ./install.sh $INSTALL_BINARY_NAME
FROM golang AS gometalinter
FROM base AS gometalinter
ENV INSTALL_BINARY_NAME=gometalinter
COPY hack/dockerfile/install/install.sh ./install.sh
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
RUN PREFIX=/opt/$INSTALL_BINARY_NAME ./install.sh $INSTALL_BINARY_NAME
FROM golang AS dockercli
FROM base AS dockercli
ENV INSTALL_BINARY_NAME=dockercli
COPY hack/dockerfile/install/install.sh ./install.sh
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
@@ -231,6 +234,8 @@ RUN apt-get update && apt-get install -y \
vim-common \
xfsprogs \
zip \
bzip2 \
xz-utils \
--no-install-recommends
COPY --from=swagger /usr/local/bin/swagger* /usr/local/bin/
COPY --from=frozen-images /docker-frozen-images /docker-frozen-images
@@ -242,7 +247,6 @@ COPY --from=runc /opt/runc/ /usr/local/bin/
COPY --from=containerd /opt/containerd/ /usr/local/bin/
COPY --from=proxy /opt/proxy/ /usr/local/bin/
COPY --from=dockercli /opt/dockercli /usr/local/cli
COPY --from=golang /usr/local/go /usr/local/go
COPY --from=registry /usr/local/bin/registry* /usr/local/bin/
COPY --from=notary /usr/local/bin/notary* /usr/local/bin/
COPY --from=criu /opt/criu/ /usr/local/

View File

@@ -1,172 +0,0 @@
# This file describes the standard way to build Docker on aarch64, using docker
#
# Usage:
#
# # Assemble the full dev environment. This is slow the first time.
# docker build -t docker -f Dockerfile.aarch64 .
#
# # Mount your source in an interactive container for quick testing:
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
#
# # Run the test suite:
# docker run --privileged docker hack/make.sh test-unit test-integration test-docker-py
#
# Note: AppArmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#
FROM debian:stretch
# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
# Packaged dependencies
RUN apt-get update && apt-get install -y \
apparmor \
apt-utils \
aufs-tools \
automake \
bash-completion \
bsdmainutils \
btrfs-tools \
build-essential \
cmake \
createrepo \
curl \
dpkg-sig \
gcc \
git \
iptables \
jq \
less \
libapparmor-dev \
libcap-dev \
libdevmapper-dev \
libnl-3-dev \
libprotobuf-c0-dev \
libprotobuf-dev \
libseccomp-dev \
libsystemd-dev \
libtool \
libudev-dev \
mercurial \
net-tools \
pigz \
pkg-config \
protobuf-compiler \
protobuf-c-compiler \
python-backports.ssl-match-hostname \
python-dev \
python-mock \
python-pip \
python-requests \
python-setuptools \
python-websocket \
python-wheel \
tar \
thin-provisioning-tools \
vim \
vim-common \
xfsprogs \
zip \
--no-install-recommends
# Install Go
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.9.4
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-arm64.tar.gz" \
| tar -xzC /usr/local
ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go
# Only install one version of the registry, because old version which support
# schema1 manifests is not working on ARM64, we should skip integration-cli
# tests for schema1 manifests on ARM64.
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& rm -rf "$GOPATH"
# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
# To run integration tests docker-pycreds is required.
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT \
&& pip install docker-pycreds==0.2.1 \
&& pip install -r test-requirements.txt
# Install yamllint for validating swagger.yaml
RUN pip install yamllint==1.5.0
# Install go-swagger for validating swagger.yaml
ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/go-swagger/go-swagger.git "$GOPATH/src/github.com/go-swagger/go-swagger" \
&& (cd "$GOPATH/src/github.com/go-swagger/go-swagger" && git checkout -q "$GO_SWAGGER_COMMIT") \
&& go build -o /usr/local/bin/swagger github.com/go-swagger/go-swagger/cmd/swagger \
&& rm -rf "$GOPATH"
# Set user.email so crosbymichael's in-container merge commits go smoothly
RUN git config --global user.email 'docker-dummy@example.com'
# Add an unprivileged user to be used for tests which need it
RUN groupadd -r docker
RUN useradd --create-home --gid docker unprivilegeduser
VOLUME /var/lib/docker
WORKDIR /go/src/github.com/docker/docker
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
# Let us use a .bashrc file
RUN ln -sfv $PWD/.bashrc ~/.bashrc
# Register Docker's bash completion.
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
busybox:1.27-glibc@sha256:8c8f261a462eead45ab8e610d3e8f7a1e4fd1cd9bed5bc0a0c386784ab105d8e \
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
# See also ensureFrozenImagesLinux() in "integration-cli/fixtures_linux_daemon_test.go" (which needs to be updated when adding images to this list)
#
# Install tomlv, vndr, runc, containerd, tini, proxy dockercli
# Please edit hack/dockerfile/install/<name>.installer to update them.
COPY hack/dockerfile/install hack/dockerfile/install
RUN for i in tomlv vndr tini gometalinter proxy dockercli runc containerd; \
do hack/dockerfile/install/install.sh $i; \
done
ENV PATH=/usr/local/cli:$PATH
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]
# Options for hack/validate/gometalinter
ENV GOMETALINTER_OPTS="--deadline=4m -j2"
# Upload docker source
COPY . /go/src/github.com/docker/docker

View File

@@ -1,155 +0,0 @@
# This file describes the standard way to build Docker on ARMv7, using docker
#
# Usage:
#
# # Assemble the full dev environment. This is slow the first time.
# docker build -t docker -f Dockerfile.armhf .
#
# # Mount your source in an interactive container for quick testing:
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
#
# # Run the test suite:
# docker run --privileged docker hack/make.sh test-unit test-integration test-docker-py
#
# Note: AppArmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#
FROM arm32v7/debian:stretch
# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
# Packaged dependencies
RUN apt-get update && apt-get install -y \
apparmor \
aufs-tools \
automake \
bash-completion \
btrfs-tools \
build-essential \
createrepo \
curl \
cmake \
dpkg-sig \
git \
iptables \
jq \
net-tools \
libapparmor-dev \
libcap-dev \
libdevmapper-dev \
libseccomp-dev \
libsystemd-dev \
libtool \
libudev-dev \
mercurial \
pigz \
pkg-config \
python-backports.ssl-match-hostname \
python-dev \
python-mock \
python-pip \
python-requests \
python-setuptools \
python-websocket \
python-wheel \
xfsprogs \
tar \
thin-provisioning-tools \
vim-common \
--no-install-recommends \
&& pip install awscli==1.10.15
# Install Go
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.9.4
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" \
| tar -xzC /usr/local
ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go
# We're building for armhf, which is ARMv7, so let's be explicit about that
ENV GOARCH arm
ENV GOARM 7
# Install two versions of the registry. The first is an older version that
# only supports schema1 manifests. The second is a newer version that supports
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
&& rm -rf "$GOPATH"
# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
# To run integration tests docker-pycreds is required.
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT \
&& pip install docker-pycreds==0.2.1 \
&& pip install -r test-requirements.txt
# Set user.email so crosbymichael's in-container merge commits go smoothly
RUN git config --global user.email 'docker-dummy@example.com'
# Add an unprivileged user to be used for tests which need it
RUN groupadd -r docker
RUN useradd --create-home --gid docker unprivilegeduser
VOLUME /var/lib/docker
WORKDIR /go/src/github.com/docker/docker
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
# Let us use a .bashrc file
RUN ln -sfv $PWD/.bashrc ~/.bashrc
# Register Docker's bash completion.
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
busybox:1.27-glibc@sha256:8c8f261a462eead45ab8e610d3e8f7a1e4fd1cd9bed5bc0a0c386784ab105d8e \
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
# See also ensureFrozenImagesLinux() in "integration-cli/fixtures_linux_daemon_test.go" (which needs to be updated when adding images to this list)
# Install tomlv, vndr, runc, containerd, tini, proxy dockercli
# Please edit hack/dockerfile/install/<name>.installer to update them.
COPY hack/dockerfile/install hack/dockerfile/install
RUN for i in tomlv vndr tini gometalinter proxy dockercli runc containerd; \
do hack/dockerfile/install/install.sh $i; \
done
ENV PATH=/usr/local/cli:$PATH
ENTRYPOINT ["hack/dind"]
# Options for hack/validate/gometalinter
ENV GOMETALINTER_OPTS="--deadline=10m -j2"
# Upload docker source
COPY . /go/src/github.com/docker/docker

View File

@@ -17,7 +17,8 @@ WORKDIR /go/src/github.com/docker/docker/
COPY contrib/download-frozen-image-v2.sh contrib/download-frozen-image-v2.sh
RUN contrib/download-frozen-image-v2.sh /output/docker-frozen-images \
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
busybox:1.27-glibc@sha256:8c8f261a462eead45ab8e610d3e8f7a1e4fd1cd9bed5bc0a0c386784ab105d8e \
busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0 \
busybox:glibc@sha256:0b55a30394294ab23b9afd58fab94e61a923f5834fba7ddbae7f8e0c11ba85e6 \
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c

View File

@@ -1,151 +0,0 @@
# This file describes the standard way to build Docker on ppc64le, using docker
#
# Usage:
#
# # Assemble the full dev environment. This is slow the first time.
# docker build -t docker -f Dockerfile.ppc64le .
#
# # Mount your source in an interactive container for quick testing:
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
#
# # Run the test suite:
# docker run --privileged docker hack/make.sh test-unit test-integration test-docker-py
#
# Note: AppArmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#
FROM ppc64le/debian:stretch
# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
# Packaged dependencies
RUN apt-get update && apt-get install -y \
apparmor \
apt-utils \
aufs-tools \
automake \
bash-completion \
btrfs-tools \
build-essential \
cmake \
createrepo \
curl \
dpkg-sig \
git \
iptables \
jq \
net-tools \
libapparmor-dev \
libcap-dev \
libdevmapper-dev \
libseccomp-dev \
libsystemd-dev \
libtool \
libudev-dev \
mercurial \
pigz \
pkg-config \
python-backports.ssl-match-hostname \
python-dev \
python-mock \
python-pip \
python-requests \
python-setuptools \
python-websocket \
python-wheel \
xfsprogs \
tar \
thin-provisioning-tools \
vim-common \
--no-install-recommends
# Install Go
# NOTE: official ppc64le go binaries weren't available until go 1.6.4 and 1.7.4
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.9.4
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" \
| tar -xzC /usr/local
ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go
# Install two versions of the registry. The first is an older version that
# only supports schema1 manifests. The second is a newer version that supports
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
&& rm -rf "$GOPATH"
# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
# To run integration tests docker-pycreds is required.
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT \
&& pip install docker-pycreds==0.2.1 \
&& pip install -r test-requirements.txt
# Set user.email so crosbymichael's in-container merge commits go smoothly
RUN git config --global user.email 'docker-dummy@example.com'
# Add an unprivileged user to be used for tests which need it
RUN groupadd -r docker
RUN useradd --create-home --gid docker unprivilegeduser
VOLUME /var/lib/docker
WORKDIR /go/src/github.com/docker/docker
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
# Let us use a .bashrc file
RUN ln -sfv $PWD/.bashrc ~/.bashrc
# Register Docker's bash completion.
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
busybox:1.27-glibc@sha256:8c8f261a462eead45ab8e610d3e8f7a1e4fd1cd9bed5bc0a0c386784ab105d8e \
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
# See also ensureFrozenImagesLinux() in "integration-cli/fixtures_linux_daemon_test.go" (which needs to be updated when adding images to this list)
# Install tomlv, vndr, runc, containerd, tini, proxy dockercli
# Please edit hack/dockerfile/install/<name>.installer to update them.
COPY hack/dockerfile/install hack/dockerfile/install
RUN for i in tomlv vndr tini gometalinter proxy dockercli runc containerd; \
do hack/dockerfile/install/install.sh $i; \
done
ENV PATH=/usr/local/cli:$PATH
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]
# Upload docker source
COPY . /go/src/github.com/docker/docker

View File

@@ -1,145 +0,0 @@
# This file describes the standard way to build Docker on s390x, using docker
#
# Usage:
#
# # Assemble the full dev environment. This is slow the first time.
# docker build -t docker -f Dockerfile.s390x .
#
# # Mount your source in an interactive container for quick testing:
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
#
# # Run the test suite:
# docker run --privileged docker hack/make.sh test-unit test-integration test-docker-py
#
# Note: AppArmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#
FROM s390x/debian:stretch
# Packaged dependencies
RUN apt-get update && apt-get install -y \
apparmor \
apt-utils \
aufs-tools \
automake \
bash-completion \
btrfs-tools \
build-essential \
cmake \
createrepo \
curl \
dpkg-sig \
git \
iptables \
jq \
net-tools \
libapparmor-dev \
libcap-dev \
libdevmapper-dev \
libseccomp-dev \
libsystemd-dev \
libtool \
libudev-dev \
mercurial \
pigz \
pkg-config \
python-backports.ssl-match-hostname \
python-dev \
python-mock \
python-pip \
python-requests \
python-setuptools \
python-websocket \
python-wheel \
xfsprogs \
tar \
thin-provisioning-tools \
vim-common \
--no-install-recommends
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
ENV GO_VERSION 1.9.4
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" \
| tar -xzC /usr/local
ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go
# Install two versions of the registry. The first is an older version that
# only supports schema1 manifests. The second is a newer version that supports
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
&& rm -rf "$GOPATH"
# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
# To run integration tests docker-pycreds is required.
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT \
&& pip install docker-pycreds==0.2.1 \
&& pip install -r test-requirements.txt
# Set user.email so crosbymichael's in-container merge commits go smoothly
RUN git config --global user.email 'docker-dummy@example.com'
# Add an unprivileged user to be used for tests which need it
RUN groupadd -r docker
RUN useradd --create-home --gid docker unprivilegeduser
VOLUME /var/lib/docker
WORKDIR /go/src/github.com/docker/docker
ENV DOCKER_BUILDTAGS apparmor selinux seccomp
# Let us use a .bashrc file
RUN ln -sfv $PWD/.bashrc ~/.bashrc
# Register Docker's bash completion.
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
busybox:1.27-glibc@sha256:8c8f261a462eead45ab8e610d3e8f7a1e4fd1cd9bed5bc0a0c386784ab105d8e \
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
# See also ensureFrozenImagesLinux() in "integration-cli/fixtures_linux_daemon_test.go" (which needs to be updated when adding images to this list)
# Install tomlv, vndr, runc, containerd, tini, proxy dockercli
# Please edit hack/dockerfile/install/<name>.installer to update them.
COPY hack/dockerfile/install hack/dockerfile/install
RUN for i in tomlv vndr tini gometalinter proxy dockercli runc containerd; \
do hack/dockerfile/install/install.sh $i; \
done
ENV PATH=/usr/local/cli:$PATH
# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]
# Upload docker source
COPY . /go/src/github.com/docker/docker

View File

@@ -3,6 +3,7 @@ package container // import "github.com/docker/docker/container"
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
@@ -74,6 +75,7 @@ func TestContainerSecretReferenceDestTarget(t *testing.T) {
func TestContainerLogPathSetForJSONFileLogger(t *testing.T) {
containerRoot, err := ioutil.TempDir("", "TestContainerLogPathSetForJSONFileLogger")
require.NoError(t, err)
defer os.RemoveAll(containerRoot)
c := &Container{
Config: &container.Config{},
@@ -86,8 +88,9 @@ func TestContainerLogPathSetForJSONFileLogger(t *testing.T) {
Root: containerRoot,
}
_, err = c.StartLogger()
logger, err := c.StartLogger()
require.NoError(t, err)
defer logger.Close()
expectedLogPath, err := filepath.Abs(filepath.Join(containerRoot, fmt.Sprintf("%s-json.log", c.ID)))
require.NoError(t, err)
@@ -97,6 +100,7 @@ func TestContainerLogPathSetForJSONFileLogger(t *testing.T) {
func TestContainerLogPathSetForRingLogger(t *testing.T) {
containerRoot, err := ioutil.TempDir("", "TestContainerLogPathSetForRingLogger")
require.NoError(t, err)
defer os.RemoveAll(containerRoot)
c := &Container{
Config: &container.Config{},
@@ -112,8 +116,9 @@ func TestContainerLogPathSetForRingLogger(t *testing.T) {
Root: containerRoot,
}
_, err = c.StartLogger()
logger, err := c.StartLogger()
require.NoError(t, err)
defer logger.Close()
expectedLogPath, err := filepath.Abs(filepath.Join(containerRoot, fmt.Sprintf("%s-json.log", c.ID)))
require.NoError(t, err)

View File

@@ -18,6 +18,7 @@ import (
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
containerpkg "github.com/docker/docker/container"
"github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/cluster/convert"
executorpkg "github.com/docker/docker/daemon/cluster/executor"
"github.com/docker/libnetwork"
@@ -155,7 +156,11 @@ func (c *containerAdapter) createNetworks(ctx context.Context) error {
if _, ok := err.(libnetwork.NetworkNameError); ok {
continue
}
// We will continue if CreateManagedNetwork returns PredefinedNetworkError error.
// Other callers still can treat it as Error.
if _, ok := err.(daemon.PredefinedNetworkError); ok {
continue
}
return err
}
}

View File

@@ -2223,6 +2223,38 @@ func (devices *DeviceSet) cancelDeferredRemoval(info *devInfo) error {
return err
}
func (devices *DeviceSet) unmountAndDeactivateAll(dir string) {
files, err := ioutil.ReadDir(dir)
if err != nil {
logrus.Warnf("devmapper: unmountAndDeactivate: %s", err)
return
}
for _, d := range files {
if !d.IsDir() {
continue
}
name := d.Name()
fullname := path.Join(dir, name)
// We use MNT_DETACH here in case it is still busy in some running
// container. This means it'll go away from the global scope directly,
// and the device will be released when that container dies.
if err := unix.Unmount(fullname, unix.MNT_DETACH); err != nil && err != unix.EINVAL {
logrus.Warnf("devmapper: Shutdown unmounting %s, error: %s", fullname, err)
}
if devInfo, err := devices.lookupDevice(name); err != nil {
logrus.Debugf("devmapper: Shutdown lookup device %s, error: %s", name, err)
} else {
if err := devices.deactivateDevice(devInfo); err != nil {
logrus.Debugf("devmapper: Shutdown deactivate %s, error: %s", devInfo.Hash, err)
}
}
}
}
// Shutdown shuts down the device by unmounting the root.
func (devices *DeviceSet) Shutdown(home string) error {
logrus.Debugf("devmapper: [deviceset %s] Shutdown()", devices.devicePrefix)
@@ -2244,45 +2276,7 @@ func (devices *DeviceSet) Shutdown(home string) error {
// will be killed and we will not get a chance to save deviceset
// metadata. Hence save this early before trying to deactivate devices.
devices.saveDeviceSetMetaData()
// ignore the error since it's just a best effort to not try to unmount something that's mounted
mounts, _ := mount.GetMounts()
mounted := make(map[string]bool, len(mounts))
for _, mnt := range mounts {
mounted[mnt.Mountpoint] = true
}
if err := filepath.Walk(path.Join(home, "mnt"), func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
return nil
}
if mounted[p] {
// We use MNT_DETACH here in case it is still busy in some running
// container. This means it'll go away from the global scope directly,
// and the device will be released when that container dies.
if err := unix.Unmount(p, unix.MNT_DETACH); err != nil {
logrus.Debugf("devmapper: Shutdown unmounting %s, error: %s", p, err)
}
}
if devInfo, err := devices.lookupDevice(path.Base(p)); err != nil {
logrus.Debugf("devmapper: Shutdown lookup device %s, error: %s", path.Base(p), err)
} else {
if err := devices.deactivateDevice(devInfo); err != nil {
logrus.Debugf("devmapper: Shutdown deactivate %s , error: %s", devInfo.Hash, err)
}
}
return nil
}); err != nil && !os.IsNotExist(err) {
devices.Unlock()
return err
}
devices.unmountAndDeactivateAll(path.Join(home, "mnt"))
devices.Unlock()
info, _ := devices.lookupDeviceWithLock("")

View File

@@ -9,16 +9,16 @@ import (
"path"
"strconv"
"github.com/sirupsen/logrus"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/devicemapper"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/locker"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/system"
units "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func init() {
@@ -122,12 +122,18 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
// Cleanup unmounts a device.
func (d *Driver) Cleanup() error {
err := d.DeviceSet.Shutdown(d.home)
umountErr := mount.RecursiveUnmount(d.home)
if err2 := mount.RecursiveUnmount(d.home); err == nil {
err = err2
// in case we have two errors, prefer the one from Shutdown()
if err != nil {
return err
}
return err
if umountErr != nil {
return errors.Wrapf(umountErr, "error unmounting %s", d.home)
}
return nil
}
// CreateReadWrite creates a layer that is writable for use as a container
@@ -145,7 +151,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
return d.DeviceSet.AddDevice(id, parent, storageOpt)
}
// Remove removes a device with a given id, unmounts the filesystem.
// Remove removes a device with a given id, unmounts the filesystem, and removes the mount point.
func (d *Driver) Remove(id string) error {
d.locker.Lock(id)
defer d.locker.Unlock(id)
@@ -160,7 +166,21 @@ func (d *Driver) Remove(id string) error {
if err := d.DeviceSet.DeleteDevice(id, false); err != nil {
return fmt.Errorf("failed to remove device %s: %v", id, err)
}
return system.EnsureRemoveAll(path.Join(d.home, "mnt", id))
// Most probably the mount point is already removed on Put()
// (see DeviceSet.UnmountDevice()), but just in case it was not
// let's try to remove it here as well, ignoring errors as
// an older kernel can return EBUSY if e.g. the mount was leaked
// to other mount namespaces. A failure to remove the container's
// mount point is not important and should not be treated
// as a failure to remove the container.
mp := path.Join(d.home, "mnt", id)
err := unix.Rmdir(mp)
if err != nil && !os.IsNotExist(err) {
logrus.WithField("storage-driver", "devicemapper").Warnf("unable to remove mount point %q: %s", mp, err)
}
return nil
}
// Get mounts a device with given id into the root filesystem

View File

@@ -6,30 +6,8 @@ import (
"bytes"
"fmt"
"os"
"path/filepath"
"golang.org/x/sys/unix"
)
// FIXME: this is copy-pasted from the aufs driver.
// It should be moved into the core.
// Mounted returns true if a mount point exists.
func Mounted(mountpoint string) (bool, error) {
var mntpointSt unix.Stat_t
if err := unix.Stat(mountpoint, &mntpointSt); err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
var parentSt unix.Stat_t
if err := unix.Stat(filepath.Join(mountpoint, ".."), &parentSt); err != nil {
return false, err
}
return mntpointSt.Dev != parentSt.Dev, nil
}
type probeData struct {
fsName string
magic string

View File

@@ -95,7 +95,7 @@ func New(info logger.Info) (logger.Logger, error) {
return b, nil
}
writer, err := loggerutils.NewLogFile(info.LogPath, capval, maxFiles, marshalFunc, decodeFunc)
writer, err := loggerutils.NewLogFile(info.LogPath, capval, maxFiles, marshalFunc, decodeFunc, 0640)
if err != nil {
return nil, err
}

View File

@@ -31,13 +31,14 @@ type LogFile struct {
notifyRotate *pubsub.Publisher
marshal logger.MarshalFunc
createDecoder makeDecoderFunc
perms os.FileMode
}
type makeDecoderFunc func(rdr io.Reader) func() (*logger.Message, error)
//NewLogFile creates new LogFile
func NewLogFile(logPath string, capacity int64, maxFiles int, marshaller logger.MarshalFunc, decodeFunc makeDecoderFunc) (*LogFile, error) {
log, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
func NewLogFile(logPath string, capacity int64, maxFiles int, marshaller logger.MarshalFunc, decodeFunc makeDecoderFunc, perms os.FileMode) (*LogFile, error) {
log, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, perms)
if err != nil {
return nil, err
}
@@ -55,6 +56,7 @@ func NewLogFile(logPath string, capacity int64, maxFiles int, marshaller logger.
notifyRotate: pubsub.NewPublisher(0, 1),
marshal: marshaller,
createDecoder: decodeFunc,
perms: perms,
}, nil
}
@@ -100,7 +102,7 @@ func (w *LogFile) checkCapacityAndRotate() error {
if err := rotate(name, w.maxFiles); err != nil {
return err
}
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0640)
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, w.perms)
if err != nil {
return err
}

View File

@@ -93,7 +93,10 @@ func (r *RingLogger) Close() error {
}
if err := r.l.Log(msg); err != nil {
logrus.WithField("driver", r.l.Name()).WithField("container", r.logInfo.ContainerID).Errorf("Error writing log message: %v", r.l)
logrus.WithField("driver", r.l.Name()).
WithField("container", r.logInfo.ContainerID).
WithError(err).
Errorf("Error writing log message")
logErr = true
}
}
@@ -114,7 +117,10 @@ func (r *RingLogger) run() {
return
}
if err := r.l.Log(msg); err != nil {
logrus.WithField("driver", r.l.Name()).WithField("container", r.logInfo.ContainerID).Errorf("Error writing log message: %v", r.l)
logrus.WithField("driver", r.l.Name()).
WithField("container", r.logInfo.ContainerID).
WithError(err).
Errorf("Error writing log message")
}
}
}

View File

@@ -24,6 +24,16 @@ import (
"golang.org/x/net/context"
)
// PredefinedNetworkError is returned when user tries to create predefined network that already exists.
type PredefinedNetworkError string
func (pnr PredefinedNetworkError) Error() string {
return fmt.Sprintf("operation is not permitted on predefined %s network ", string(pnr))
}
// Forbidden denotes the type of this error
func (pnr PredefinedNetworkError) Forbidden() {}
// NetworkControllerEnabled checks if the networking stack is enabled.
// This feature depends on OS primitives and it's disabled in systems like Windows.
func (daemon *Daemon) NetworkControllerEnabled() bool {
@@ -267,9 +277,8 @@ func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.N
}
func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) {
if runconfig.IsPreDefinedNetwork(create.Name) && !agent {
err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name)
return nil, errdefs.Forbidden(err)
if runconfig.IsPreDefinedNetwork(create.Name) {
return nil, PredefinedNetworkError(create.Name)
}
var warning string

View File

@@ -667,7 +667,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
if s.Root.Readonly {
for i, m := range s.Mounts {
switch m.Destination {
case "/proc", "/dev/pts", "/dev/mqueue", "/dev":
case "/proc", "/dev/pts", "/dev/shm", "/dev/mqueue", "/dev":
continue
}
if _, ok := userMounts[m.Destination]; !ok {

View File

@@ -48,3 +48,41 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
err = setMounts(&d, &s, c, ms)
assert.NoError(t, err)
}
// TestIpcPrivateVsReadonly checks that in case of IpcMode: private
// and ReadonlyRootfs: true (as in "docker run --ipc private --read-only")
// the resulting /dev/shm mount is NOT made read-only.
// https://github.com/moby/moby/issues/36503
func TestIpcPrivateVsReadonly(t *testing.T) {
d := Daemon{
// some empty structs to avoid getting a panic
// caused by a null pointer dereference
idMappings: &idtools.IDMappings{},
configStore: &config.Config{},
}
c := &container.Container{
HostConfig: &containertypes.HostConfig{
IpcMode: containertypes.IpcMode("private"),
ReadonlyRootfs: true,
},
}
// We can't call createSpec() so mimick the minimal part
// of its code flow, just enough to reproduce the issue.
ms, err := d.setupMounts(c)
assert.NoError(t, err)
s := oci.DefaultSpec()
s.Root.Readonly = c.HostConfig.ReadonlyRootfs
err = setMounts(&d, &s, c, ms)
assert.NoError(t, err)
// Find the /dev/shm mount in ms, check it does not have ro
for _, m := range s.Mounts {
if m.Destination != "/dev/shm" {
continue
}
assert.Equal(t, false, inSlice(m.Options, "ro"))
}
}

View File

@@ -1,6 +1,8 @@
package stats // import "github.com/docker/docker/daemon/stats"
import (
"bufio"
"sync"
"time"
"github.com/docker/docker/api/types"
@@ -9,6 +11,37 @@ import (
"github.com/sirupsen/logrus"
)
// Collector manages and provides container resource stats
type Collector struct {
m sync.Mutex
supervisor supervisor
interval time.Duration
publishers map[*container.Container]*pubsub.Publisher
bufReader *bufio.Reader
// The following fields are not set on Windows currently.
clockTicksPerSecond uint64
}
// NewCollector creates a stats collector that will poll the supervisor with the specified interval
func NewCollector(supervisor supervisor, interval time.Duration) *Collector {
s := &Collector{
interval: interval,
supervisor: supervisor,
publishers: make(map[*container.Container]*pubsub.Publisher),
bufReader: bufio.NewReaderSize(nil, 128),
}
platformNewStatsCollector(s)
return s
}
type supervisor interface {
// GetContainerStats collects all the stats related to a container
GetContainerStats(container *container.Container) (*types.StatsJSON, error)
}
// Collect registers the container with the collector and adds it to
// the event loop for collection on the specified interval returning
// a channel for the subscriber to receive on.
@@ -57,7 +90,7 @@ func (s *Collector) Run() {
// it will grow enough in first iteration
var pairs []publishersPair
for range time.Tick(s.interval) {
for {
// it does not make sense in the first iteration,
// but saves allocations in further iterations
pairs = pairs[:0]
@@ -72,12 +105,6 @@ func (s *Collector) Run() {
continue
}
systemUsage, err := s.getSystemCPUUsage()
if err != nil {
logrus.Errorf("collecting system cpu usage: %v", err)
continue
}
onlineCPUs, err := s.getNumberOnlineCPUs()
if err != nil {
logrus.Errorf("collecting system online cpu count: %v", err)
@@ -89,6 +116,14 @@ func (s *Collector) Run() {
switch err.(type) {
case nil:
// Sample system CPU usage close to container usage to avoid
// noise in metric calculations.
systemUsage, err := s.getSystemCPUUsage()
if err != nil {
logrus.WithError(err).WithField("container_id", pair.container.ID).Errorf("collecting system cpu usage")
continue
}
// FIXME: move to containerd on Linux (not Windows)
stats.CPUStats.SystemUsage = systemUsage
stats.CPUStats.OnlineCPUs = onlineCPUs
@@ -106,6 +141,8 @@ func (s *Collector) Run() {
logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
}
}
time.Sleep(s.interval)
}
}

View File

@@ -1,42 +0,0 @@
package stats // import "github.com/docker/docker/daemon/stats"
import (
"bufio"
"sync"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/container"
"github.com/docker/docker/pkg/pubsub"
)
type supervisor interface {
// GetContainerStats collects all the stats related to a container
GetContainerStats(container *container.Container) (*types.StatsJSON, error)
}
// NewCollector creates a stats collector that will poll the supervisor with the specified interval
func NewCollector(supervisor supervisor, interval time.Duration) *Collector {
s := &Collector{
interval: interval,
supervisor: supervisor,
publishers: make(map[*container.Container]*pubsub.Publisher),
bufReader: bufio.NewReaderSize(nil, 128),
}
platformNewStatsCollector(s)
return s
}
// Collector manages and provides container resource stats
type Collector struct {
m sync.Mutex
supervisor supervisor
interval time.Duration
publishers map[*container.Container]*pubsub.Publisher
bufReader *bufio.Reader
// The following fields are not set on Windows currently.
clockTicksPerSecond uint64
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/docker/docker/registry"
"github.com/docker/libtrust"
"github.com/opencontainers/go-digest"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context"
)
@@ -86,7 +87,8 @@ type ImagePushConfig struct {
type ImageConfigStore interface {
Put([]byte) (digest.Digest, error)
Get(digest.Digest) ([]byte, error)
RootFSAndOSFromConfig([]byte) (*image.RootFS, string, error)
RootFSFromConfig([]byte) (*image.RootFS, error)
PlatformFromConfig([]byte) (*specs.Platform, error)
}
// PushLayerProvider provides layers to be pushed by ChainID.
@@ -140,18 +142,26 @@ func (s *imageConfigStore) Get(d digest.Digest) ([]byte, error) {
return img.RawJSON(), nil
}
func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
func (s *imageConfigStore) RootFSFromConfig(c []byte) (*image.RootFS, error) {
var unmarshalledConfig image.Image
if err := json.Unmarshal(c, &unmarshalledConfig); err != nil {
return nil, "", err
return nil, err
}
return unmarshalledConfig.RootFS, nil
}
func (s *imageConfigStore) PlatformFromConfig(c []byte) (*specs.Platform, error) {
var unmarshalledConfig image.Image
if err := json.Unmarshal(c, &unmarshalledConfig); err != nil {
return nil, err
}
// fail immediately on Windows when downloading a non-Windows image
// and vice versa. Exception on Windows if Linux Containers are enabled.
if runtime.GOOS == "windows" && unmarshalledConfig.OS == "linux" && !system.LCOWSupported() {
return nil, "", fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
return nil, fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
} else if runtime.GOOS != "windows" && unmarshalledConfig.OS == "windows" {
return nil, "", fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
return nil, fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
}
os := unmarshalledConfig.OS
@@ -159,9 +169,9 @@ func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, strin
os = runtime.GOOS
}
if !system.IsOSSupported(os) {
return nil, "", system.ErrNotSupportedOperatingSystem
return nil, system.ErrNotSupportedOperatingSystem
}
return unmarshalledConfig.RootFS, os, nil
return &specs.Platform{OS: os, OSVersion: unmarshalledConfig.OSVersion}, nil
}
type storeLayerProvider struct {

View File

@@ -30,6 +30,7 @@ import (
refstore "github.com/docker/docker/reference"
"github.com/docker/docker/registry"
digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
@@ -588,7 +589,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
downloadedRootFS *image.RootFS // rootFS from registered layers
configRootFS *image.RootFS // rootFS from configuration
release func() // release resources from rootFS download
configOS string // for LCOW when registering downloaded layers
configPlatform *specs.Platform // for LCOW when registering downloaded layers
)
// https://github.com/docker/docker/issues/24766 - Err on the side of caution,
@@ -600,14 +601,16 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
// check to block Windows images being pulled on Linux is implemented, it
// may be necessary to perform the same type of serialisation.
if runtime.GOOS == "windows" {
configJSON, configRootFS, configOS, err = receiveConfig(p.config.ImageStore, configChan, configErrChan)
configJSON, configRootFS, configPlatform, err = receiveConfig(p.config.ImageStore, configChan, configErrChan)
if err != nil {
return "", "", err
}
if configRootFS == nil {
return "", "", errRootFSInvalid
}
if err := checkImageCompatibility(configPlatform.OS, configPlatform.OSVersion); err != nil {
return "", "", err
}
if len(descriptors) != len(configRootFS.DiffIDs) {
return "", "", errRootFSMismatch
@@ -615,8 +618,8 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
// Early bath if the requested OS doesn't match that of the configuration.
// This avoids doing the download, only to potentially fail later.
if !strings.EqualFold(configOS, requestedOS) {
return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configOS, requestedOS)
if !strings.EqualFold(configPlatform.OS, requestedOS) {
return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configPlatform.OS, requestedOS)
}
// Populate diff ids in descriptors to avoid downloading foreign layers
@@ -698,16 +701,20 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
return imageID, manifestDigest, nil
}
func receiveConfig(s ImageConfigStore, configChan <-chan []byte, errChan <-chan error) ([]byte, *image.RootFS, string, error) {
func receiveConfig(s ImageConfigStore, configChan <-chan []byte, errChan <-chan error) ([]byte, *image.RootFS, *specs.Platform, error) {
select {
case configJSON := <-configChan:
rootfs, os, err := s.RootFSAndOSFromConfig(configJSON)
rootfs, err := s.RootFSFromConfig(configJSON)
if err != nil {
return nil, nil, "", err
return nil, nil, nil, err
}
return configJSON, rootfs, os, nil
platform, err := s.PlatformFromConfig(configJSON)
if err != nil {
return nil, nil, nil, err
}
return configJSON, rootfs, platform, nil
case err := <-errChan:
return nil, nil, "", err
return nil, nil, nil, err
// Don't need a case for ctx.Done in the select because cancellation
// will trigger an error in p.pullSchema2ImageConfig.
}
@@ -736,6 +743,10 @@ func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mf
}
manifestDigest := manifestMatches[0].Digest
if err := checkImageCompatibility(manifestMatches[0].Platform.OS, manifestMatches[0].Platform.OSVersion); err != nil {
return "", "", err
}
manSvc, err := p.repo.Manifests(ctx)
if err != nil {
return "", "", err

View File

@@ -27,3 +27,8 @@ func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []m
}
return matches
}
// checkImageCompatibility is a Windows-specific function. No-op on Linux
func checkImageCompatibility(imageOS, imageOSVersion string) error {
return nil
}

View File

@@ -1,11 +1,13 @@
package distribution // import "github.com/docker/docker/distribution"
import (
"errors"
"fmt"
"net/http"
"os"
"runtime"
"sort"
"strconv"
"strings"
"github.com/docker/distribution"
@@ -63,7 +65,6 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo
func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []manifestlist.ManifestDescriptor {
osVersion := ""
if os == "windows" {
// TODO: Add UBR (Update Build Release) component after build
version := system.GetOSVersion()
osVersion = fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build)
logrus.Debugf("will prefer entries with version %s", osVersion)
@@ -71,10 +72,11 @@ func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []m
var matches []manifestlist.ManifestDescriptor
for _, manifestDescriptor := range manifests {
// TODO: Consider filtering out greater versions, including only greater UBR
if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == os {
matches = append(matches, manifestDescriptor)
logrus.Debugf("found match for %s/%s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
logrus.Debugf("found match for %s/%s %s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
} else {
logrus.Debugf("ignoring %s/%s %s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
}
}
if os == "windows" {
@@ -107,3 +109,22 @@ func (mbv manifestsByVersion) Len() int {
func (mbv manifestsByVersion) Swap(i, j int) {
mbv.list[i], mbv.list[j] = mbv.list[j], mbv.list[i]
}
// checkImageCompatibility blocks pulling incompatible images based on a later OS build
// Fixes https://github.com/moby/moby/issues/36184.
func checkImageCompatibility(imageOS, imageOSVersion string) error {
if imageOS == "windows" {
hostOSV := system.GetOSVersion()
splitImageOSVersion := strings.Split(imageOSVersion, ".") // eg 10.0.16299.nnnn
if len(splitImageOSVersion) >= 3 {
if imageOSBuild, err := strconv.Atoi(splitImageOSVersion[2]); err == nil {
if imageOSBuild > int(hostOSV.Build) {
errMsg := fmt.Sprintf("a Windows version %s.%s.%s-based image is incompatible with a %s host", splitImageOSVersion[0], splitImageOSVersion[1], splitImageOSVersion[2], hostOSV.ToString())
logrus.Debugf(errMsg)
return errors.New(errMsg)
}
}
}
}
return nil
}

View File

@@ -118,12 +118,17 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
return fmt.Errorf("could not find image from tag %s: %v", reference.FamiliarString(ref), err)
}
rootfs, os, err := p.config.ImageStore.RootFSAndOSFromConfig(imgConfig)
rootfs, err := p.config.ImageStore.RootFSFromConfig(imgConfig)
if err != nil {
return fmt.Errorf("unable to get rootfs for image %s: %s", reference.FamiliarString(ref), err)
}
l, err := p.config.LayerStores[os].Get(rootfs.ChainID())
platform, err := p.config.ImageStore.PlatformFromConfig(imgConfig)
if err != nil {
return fmt.Errorf("unable to get platform for image %s: %s", reference.FamiliarString(ref), err)
}
l, err := p.config.LayerStores[platform.OS].Get(rootfs.ChainID())
if err != nil {
return fmt.Errorf("failed to get top layer from image: %v", err)
}

View File

@@ -35,7 +35,7 @@ type ErrForbidden interface {
// ErrSystem signals that some internal error occurred.
// An example of this would be a failed mount request.
type ErrSystem interface {
ErrSystem()
System()
}
// ErrNotModified signals that an action can't be performed because it's already in the desired state

View File

@@ -12,6 +12,9 @@ type causal interface {
}
func TestNotFound(t *testing.T) {
if IsNotFound(errTest) {
t.Fatalf("did not expect not found error, got %T", errTest)
}
e := NotFound(errTest)
if !IsNotFound(e) {
t.Fatalf("expected not found error, got: %T", e)
@@ -22,6 +25,9 @@ func TestNotFound(t *testing.T) {
}
func TestConflict(t *testing.T) {
if IsConflict(errTest) {
t.Fatalf("did not expect conflcit error, got %T", errTest)
}
e := Conflict(errTest)
if !IsConflict(e) {
t.Fatalf("expected conflcit error, got: %T", e)
@@ -32,6 +38,9 @@ func TestConflict(t *testing.T) {
}
func TestForbidden(t *testing.T) {
if IsForbidden(errTest) {
t.Fatalf("did not expect forbidden error, got %T", errTest)
}
e := Forbidden(errTest)
if !IsForbidden(e) {
t.Fatalf("expected forbidden error, got: %T", e)
@@ -42,6 +51,9 @@ func TestForbidden(t *testing.T) {
}
func TestInvalidParameter(t *testing.T) {
if IsInvalidParameter(errTest) {
t.Fatalf("did not expect invalid argument error, got %T", errTest)
}
e := InvalidParameter(errTest)
if !IsInvalidParameter(e) {
t.Fatalf("expected invalid argument error, got %T", e)
@@ -52,6 +64,9 @@ func TestInvalidParameter(t *testing.T) {
}
func TestNotImplemented(t *testing.T) {
if IsNotImplemented(errTest) {
t.Fatalf("did not expect not implemented error, got %T", errTest)
}
e := NotImplemented(errTest)
if !IsNotImplemented(e) {
t.Fatalf("expected not implemented error, got %T", e)
@@ -62,6 +77,9 @@ func TestNotImplemented(t *testing.T) {
}
func TestNotModified(t *testing.T) {
if IsNotModified(errTest) {
t.Fatalf("did not expect not modified error, got %T", errTest)
}
e := NotModified(errTest)
if !IsNotModified(e) {
t.Fatalf("expected not modified error, got %T", e)
@@ -72,6 +90,9 @@ func TestNotModified(t *testing.T) {
}
func TestAlreadyExists(t *testing.T) {
if IsAlreadyExists(errTest) {
t.Fatalf("did not expect already exists error, got %T", errTest)
}
e := AlreadyExists(errTest)
if !IsAlreadyExists(e) {
t.Fatalf("expected already exists error, got %T", e)
@@ -82,6 +103,9 @@ func TestAlreadyExists(t *testing.T) {
}
func TestUnauthorized(t *testing.T) {
if IsUnauthorized(errTest) {
t.Fatalf("did not expect unauthorized error, got %T", errTest)
}
e := Unauthorized(errTest)
if !IsUnauthorized(e) {
t.Fatalf("expected unauthorized error, got %T", e)
@@ -92,6 +116,9 @@ func TestUnauthorized(t *testing.T) {
}
func TestUnknown(t *testing.T) {
if IsUnknown(errTest) {
t.Fatalf("did not expect unknown error, got %T", errTest)
}
e := Unknown(errTest)
if !IsUnknown(e) {
t.Fatalf("expected unknown error, got %T", e)
@@ -102,9 +129,12 @@ func TestUnknown(t *testing.T) {
}
func TestCancelled(t *testing.T) {
if IsCancelled(errTest) {
t.Fatalf("did not expect cancelled error, got %T", errTest)
}
e := Cancelled(errTest)
if !IsCancelled(e) {
t.Fatalf("expected canclled error, got %T", e)
t.Fatalf("expected cancelled error, got %T", e)
}
if cause := e.(causal).Cause(); cause != errTest {
t.Fatalf("causual should be errTest, got: %v", cause)
@@ -112,6 +142,9 @@ func TestCancelled(t *testing.T) {
}
func TestDeadline(t *testing.T) {
if IsDeadline(errTest) {
t.Fatalf("did not expect deadline error, got %T", errTest)
}
e := Deadline(errTest)
if !IsDeadline(e) {
t.Fatalf("expected deadline error, got %T", e)
@@ -121,7 +154,10 @@ func TestDeadline(t *testing.T) {
}
}
func TestIsDataLoss(t *testing.T) {
func TestDataLoss(t *testing.T) {
if IsDataLoss(errTest) {
t.Fatalf("did not expect data loss error, got %T", errTest)
}
e := DataLoss(errTest)
if !IsDataLoss(e) {
t.Fatalf("expected data loss error, got %T", e)
@@ -130,3 +166,29 @@ func TestIsDataLoss(t *testing.T) {
t.Fatalf("causual should be errTest, got: %v", cause)
}
}
func TestUnavailable(t *testing.T) {
if IsUnavailable(errTest) {
t.Fatalf("did not expect unavaillable error, got %T", errTest)
}
e := Unavailable(errTest)
if !IsUnavailable(e) {
t.Fatalf("expected unavaillable error, got %T", e)
}
if cause := e.(causal).Cause(); cause != errTest {
t.Fatalf("causual should be errTest, got: %v", cause)
}
}
func TestSystem(t *testing.T) {
if IsSystem(errTest) {
t.Fatalf("did not expect system error, got %T", errTest)
}
e := System(errTest)
if !IsSystem(e) {
t.Fatalf("expected system error, got %T", e)
}
if cause := e.(causal).Cause(); cause != errTest {
t.Fatalf("causual should be errTest, got: %v", cause)
}
}

View File

@@ -21,7 +21,7 @@ func getImplementer(err error) error {
ErrDeadline,
ErrDataLoss,
ErrUnknown:
return e
return err
case causer:
return getImplementer(e.Cause())
default:

View File

@@ -14,10 +14,15 @@ install_containerd() {
(
if [ "$1" == "static" ]; then
export BUILDTAGS='static_build netgo'
export EXTRA_FLAGS='-buildmod pie'
export EXTRA_FLAGS='-buildmode=pie'
export EXTRA_LDFLAGS='-extldflags "-fno-PIC -static"'
# Reset build flags to nothing if we want a dynbinary
if [ "$1" == "dynamic" ]; then
export BUILDTAGS=''
export EXTRA_FLAGS=''
export EXTRA_LDFLAGS=''
fi
make

View File

@@ -23,6 +23,7 @@ install_proxy() {
install_proxy_dynamic() {
export PROXY_LDFLAGS="-linkmode=external" install_proxy
export BUILD_MODE="-buildmode=pie"
_install_proxy
}
@@ -31,7 +32,7 @@ _install_proxy() {
git clone https://github.com/docker/libnetwork.git "$GOPATH/src/github.com/docker/libnetwork"
cd "$GOPATH/src/github.com/docker/libnetwork"
git checkout -q "$LIBNETWORK_COMMIT"
go build -buildmode=pie -ldflags="$PROXY_LDFLAGS" -o ${PREFIX}/docker-proxy github.com/docker/libnetwork/cmd/proxy
go build $BUILD_MODE -ldflags="$PROXY_LDFLAGS" -o ${PREFIX}/docker-proxy github.com/docker/libnetwork/cmd/proxy
}

View File

@@ -1,7 +1,7 @@
#!/bin/sh
# When updating RUNC_COMMIT, also update runc in vendor.conf accordingly
RUNC_COMMIT=6c55f98695e902427906eed2c799e566e3d3dfb5
RUNC_COMMIT=4fc53a81fb7c994640722ac585fa9ca548971871
install_runc() {
# Do not build with ambient capabilities support
@@ -11,7 +11,12 @@ install_runc() {
git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc"
cd "$GOPATH/src/github.com/opencontainers/runc"
git checkout -q "$RUNC_COMMIT"
make BUILDTAGS="$RUNC_BUILDTAGS" $1
if [ -z "$1" ]; then
target=static
else
target="$1"
fi
make BUILDTAGS="$RUNC_BUILDTAGS" "$target"
mkdir -p ${PREFIX}
cp runc ${PREFIX}/docker-runc
}

View File

@@ -34,35 +34,10 @@ export DOCKER_CLIENT_GOOS="${DOCKER_CLIENT_OSARCH%/*}"
export DOCKER_CLIENT_GOARCH="${DOCKER_CLIENT_OSARCH##*/}"
DOCKER_CLIENT_GOARCH=${DOCKER_CLIENT_GOARCH:=amd64}
# Retrieve the architecture used in contrib/builder/(deb|rpm)/$PACKAGE_ARCH/
PACKAGE_ARCH='amd64'
case "${DOCKER_ENGINE_GOARCH:-$DOCKER_CLIENT_GOARCH}" in
arm)
PACKAGE_ARCH='armhf'
;;
arm64)
PACKAGE_ARCH='aarch64'
;;
amd64|ppc64le|s390x)
PACKAGE_ARCH="${DOCKER_ENGINE_GOARCH:-$DOCKER_CLIENT_GOARCH}"
;;
*)
echo >&2 "warning: not sure how to convert '$DOCKER_ENGINE_GOARCH' to a 'Docker' arch, assuming '$PACKAGE_ARCH'"
;;
esac
export PACKAGE_ARCH
DOCKERFILE='Dockerfile'
case "$PACKAGE_ARCH" in
amd64)
case "${DOCKER_ENGINE_GOOS:-$DOCKER_CLIENT_GOOS}" in
windows)
if [ "${DOCKER_ENGINE_GOOS:-$DOCKER_CLIENT_GOOS}" = "windows" ]; then
DOCKERFILE='Dockerfile.windows'
;;
esac
;;
*)
DOCKERFILE="Dockerfile.$PACKAGE_ARCH"
;;
esac
fi
export DOCKERFILE

View File

@@ -85,7 +85,7 @@ type DockerSuite struct {
}
func (s *DockerSuite) OnTimeout(c *check.C) {
if !testEnv.IsLocalDaemon() {
if testEnv.IsRemoteDaemon() {
return
}
path := filepath.Join(os.Getenv("DEST"), "docker.pid")

View File

@@ -1713,7 +1713,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) {
Type: "bind",
Source: notExistPath,
Target: destPath}}},
msg: "bind source path does not exist",
msg: "bind mount source path does not exist: " + notExistPath,
},
{
config: containertypes.Config{

View File

@@ -1,74 +0,0 @@
package main
import (
"encoding/json"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/request"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/go-check/check"
)
func (s *DockerSuite) TestEventsAPIEmptyOutput(c *check.C) {
type apiResp struct {
resp *http.Response
err error
}
chResp := make(chan *apiResp)
go func() {
resp, body, err := request.Get("/events")
body.Close()
chResp <- &apiResp{resp, err}
}()
select {
case r := <-chResp:
c.Assert(r.err, checker.IsNil)
c.Assert(r.resp.StatusCode, checker.Equals, http.StatusOK)
case <-time.After(3 * time.Second):
c.Fatal("timeout waiting for events api to respond, should have responded immediately")
}
}
func (s *DockerSuite) TestEventsAPIBackwardsCompatible(c *check.C) {
since := daemonTime(c).Unix()
ts := strconv.FormatInt(since, 10)
out := runSleepingContainer(c, "--name=foo", "-d")
containerID := strings.TrimSpace(out)
c.Assert(waitRun(containerID), checker.IsNil)
q := url.Values{}
q.Set("since", ts)
_, body, err := request.Get("/events?" + q.Encode())
c.Assert(err, checker.IsNil)
defer body.Close()
dec := json.NewDecoder(body)
var containerCreateEvent *jsonmessage.JSONMessage
for {
var event jsonmessage.JSONMessage
if err := dec.Decode(&event); err != nil {
if err == io.EOF {
break
}
c.Fatal(err)
}
if event.Status == "create" && event.ID == containerID {
containerCreateEvent = &event
break
}
}
c.Assert(containerCreateEvent, checker.Not(checker.IsNil))
c.Assert(containerCreateEvent.Status, checker.Equals, "create")
c.Assert(containerCreateEvent.ID, checker.Equals, containerID)
c.Assert(containerCreateEvent.From, checker.Equals, "busybox")
}

View File

@@ -910,6 +910,8 @@ func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) {
// Test case for 30178
func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) {
// Issue #36386 can be a independent one, which is worth further investigation.
c.Skip("Root cause of Issue #36386 is needed")
d := s.AddDaemon(c, true, true)
out, err := d.Cmd("network", "create", "-d", "overlay", "lb")

View File

@@ -1439,6 +1439,7 @@ func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) {
))
}
// FIXME(vdemeester) should be unit test
func (s *DockerSuite) TestBuildBlankName(c *check.C) {
name := "testbuildblankname"
testCases := []struct {
@@ -2066,6 +2067,7 @@ func (s *DockerSuite) TestBuildNoContext(c *check.C) {
}
}
// FIXME(vdemeester) migrate to docker/cli e2e
func (s *DockerSuite) TestBuildDockerfileStdin(c *check.C) {
name := "stdindockerfile"
tmpDir, err := ioutil.TempDir("", "fake-context")
@@ -2085,6 +2087,7 @@ CMD ["cat", "/foo"]`),
c.Assert(strings.TrimSpace(string(res)), checker.Equals, `[cat /foo]`)
}
// FIXME(vdemeester) migrate to docker/cli tests (unit or e2e)
func (s *DockerSuite) TestBuildDockerfileStdinConflict(c *check.C) {
name := "stdindockerfiletarcontext"
icmd.RunCmd(icmd.Cmd{
@@ -2401,6 +2404,7 @@ func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) {
build.WithFile("Dockerfile", dockerfile),
build.WithFile(".dockerignore", "Dockerfile\n"),
))
// FIXME(vdemeester) why twice ?
buildImageSuccessfully(c, name, build.WithBuildContext(c,
build.WithFile("Dockerfile", dockerfile),
build.WithFile(".dockerignore", "./Dockerfile\n"),
@@ -2420,6 +2424,7 @@ func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) {
build.WithFile("MyDockerfile", dockerfile),
build.WithFile(".dockerignore", "MyDockerfile\n"),
))
// FIXME(vdemeester) why twice ?
buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
build.WithFile("Dockerfile", "Should not use me"),
build.WithFile("MyDockerfile", dockerfile),
@@ -3045,6 +3050,7 @@ func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) {
buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
}
// FIXME(vdemeester) most of the from git tests could be moved to `docker/cli` e2e tests
func (s *DockerSuite) TestBuildFromGit(c *check.C) {
name := "testbuildfromgit"
git := fakegit.New(c, "repo", map[string]string{
@@ -3422,6 +3428,7 @@ func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
}
// FIXME(vdemeester) port to docker/cli e2e tests (api tests should test suppressOutput option though)
func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
// This test makes sure that -q works correctly when build is successful:
// stdout has only the image ID (long image ID) and stderr is empty.
@@ -3472,6 +3479,7 @@ func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
}
// FIXME(vdemeester) migrate to docker/cli tests
func (s *DockerSuite) TestBuildNotVerboseFailureWithNonExistImage(c *check.C) {
// This test makes sure that -q works correctly when build fails by
// comparing between the stderr output in quiet mode and in stdout
@@ -3492,6 +3500,7 @@ func (s *DockerSuite) TestBuildNotVerboseFailureWithNonExistImage(c *check.C) {
}
}
// FIXME(vdemeester) migrate to docker/cli tests
func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
// This test makes sure that -q works correctly when build fails by
// comparing between the stderr output in quiet mode and in stdout
@@ -3519,6 +3528,7 @@ func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
}
}
// FIXME(vdemeester) migrate to docker/cli tests
func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
// This test ensures that when given a wrong URL, stderr in quiet mode and
// stderr in verbose mode are identical.
@@ -3548,6 +3558,7 @@ func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
}
}
// FIXME(vdemeester) migrate to docker/cli tests
func (s *DockerSuite) TestBuildStderr(c *check.C) {
// This test just makes sure that no non-error output goes
// to stderr
@@ -3688,67 +3699,6 @@ CMD cat /foo/file`),
}
// FIXME(vdemeester) part of this should be unit test, other part should be clearer
func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) {
ctx := fakecontext.New(c, "", fakecontext.WithFiles(map[string]string{
"Dockerfile": "FROM busybox\nRUN echo from Dockerfile",
"files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile",
"files/dFile": "FROM busybox\nRUN echo from files/dFile",
"dFile": "FROM busybox\nRUN echo from dFile",
"files/dFile2": "FROM busybox\nRUN echo from files/dFile2",
}))
defer ctx.Close()
cli.Docker(cli.Args("build", "-t", "test1", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
Out: "from Dockerfile",
})
cli.Docker(cli.Args("build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
Out: "from files/Dockerfile",
})
cli.Docker(cli.Args("build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
Out: "from files/dFile",
})
cli.Docker(cli.Args("build", "--file=dFile", "-t", "test4", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
Out: "from dFile",
})
dirWithNoDockerfile, err := ioutil.TempDir(os.TempDir(), "test5")
c.Assert(err, check.IsNil)
nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile")
if _, err = os.Create(nonDockerfileFile); err != nil {
c.Fatal(err)
}
cli.Docker(cli.Args("build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
ExitCode: 1,
Err: fmt.Sprintf("unable to prepare context: the Dockerfile (%s) must be within the build context", nonDockerfileFile),
})
cli.Docker(cli.Args("build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", ".."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
Out: "from Dockerfile",
})
cli.Docker(cli.Args("build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", ".."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
Out: "from files/Dockerfile",
})
cli.Docker(cli.Args("build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", "."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "must be within the build context",
})
tmpDir := os.TempDir()
cli.Docker(cli.Args("build", "-t", "test9", ctx.Dir), cli.InDir(tmpDir)).Assert(c, icmd.Expected{
Out: "from Dockerfile",
})
cli.Docker(cli.Args("build", "-f", "dFile2", "-t", "test10", "."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
Out: "from files/dFile2",
})
}
func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) {
testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
testRequires(c, DaemonIsLinux)
@@ -3772,6 +3722,7 @@ func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) {
})
}
// FIXME(vdemeester) should migrate to docker/cli tests
func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) {
server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"baz": `FROM busybox
RUN echo from baz
@@ -3798,6 +3749,7 @@ RUN find /tmp/`}))
}
// FIXME(vdemeester) should migrate to docker/cli tests
func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) {
testRequires(c, DaemonIsLinux) // TODO Windows: This test is flaky; no idea why
ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
@@ -3840,61 +3792,6 @@ func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) {
}
}
func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) {
testRequires(c, UnixCli, DaemonIsLinux) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2)
name := "testbuilddockerfileoutsidecontext"
tmpdir, err := ioutil.TempDir("", name)
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpdir)
ctx := filepath.Join(tmpdir, "context")
if err := os.MkdirAll(ctx, 0755); err != nil {
c.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil {
c.Fatal(err)
}
wd, err := os.Getwd()
if err != nil {
c.Fatal(err)
}
defer os.Chdir(wd)
if err := os.Chdir(ctx); err != nil {
c.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil {
c.Fatal(err)
}
if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil {
c.Fatal(err)
}
if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil {
c.Fatal(err)
}
for _, dockerfilePath := range []string{
filepath.Join("..", "outsideDockerfile"),
filepath.Join(ctx, "dockerfile1"),
filepath.Join(ctx, "dockerfile2"),
} {
result := dockerCmdWithResult("build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")
result.Assert(c, icmd.Expected{
Err: "must be within the build context",
ExitCode: 1,
})
deleteImages(name)
}
os.Chdir(tmpdir)
// Path to Dockerfile should be resolved relative to working directory, not relative to context.
// There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail
out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)
if err == nil {
c.Fatalf("Expected error. Out: %s", out)
}
}
// FIXME(vdemeester) should be a unit test
func (s *DockerSuite) TestBuildSpaces(c *check.C) {
// Test to make sure that leading/trailing spaces on a command
@@ -4186,6 +4083,7 @@ func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) {
})
}
// FIXME(vdemeester) should migrate to docker/cli e2e tests
func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
testRequires(c, DaemonIsLinux)
tempDir, err := ioutil.TempDir("", "test-build-dir-is-symlink-")
@@ -5130,6 +5028,7 @@ func (s *DockerSuite) TestBuildCacheRootSource(c *check.C) {
}
// #19375
// FIXME(vdemeester) should migrate to docker/cli tests
func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) {
buildImage("gitnotcallable", cli.WithEnvironmentVariables("PATH="),
build.WithContextPath("github.com/docker/v1.10-migrator.git")).Assert(c, icmd.Expected{
@@ -6447,6 +6346,7 @@ CMD echo foo
c.Assert(strings.TrimSpace(out), checker.Equals, `["/bin/sh","-c","echo foo"]`)
}
// FIXME(vdemeester) should migrate to docker/cli tests
func (s *DockerSuite) TestBuildIidFile(c *check.C) {
tmpDir, err := ioutil.TempDir("", "TestBuildIidFile")
if err != nil {
@@ -6471,6 +6371,7 @@ ENV BAR BAZ`),
c.Assert(d.String(), checker.Equals, getIDByName(c, name))
}
// FIXME(vdemeester) should migrate to docker/cli tests
func (s *DockerSuite) TestBuildIidFileCleanupOnFail(c *check.C) {
tmpDir, err := ioutil.TempDir("", "TestBuildIidFileCleanupOnFail")
if err != nil {
@@ -6493,6 +6394,7 @@ func (s *DockerSuite) TestBuildIidFileCleanupOnFail(c *check.C) {
c.Assert(os.IsNotExist(err), check.Equals, true)
}
// FIXME(vdemeester) should migrate to docker/cli tests
func (s *DockerSuite) TestBuildIidFileSquash(c *check.C) {
testRequires(c, ExperimentalDaemon)
tmpDir, err := ioutil.TempDir("", "TestBuildIidFileSquash")

View File

@@ -1,68 +0,0 @@
// +build !windows
package main
import (
"encoding/json"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
)
func (s *DockerSwarmSuite) TestConfigInspect(c *check.C) {
d := s.AddDaemon(c, true, true)
testName := "test_config"
id := d.CreateConfig(c, swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: testName,
},
Data: []byte("TESTINGDATA"),
})
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
config := d.GetConfig(c, id)
c.Assert(config.Spec.Name, checker.Equals, testName)
out, err := d.Cmd("config", "inspect", testName)
c.Assert(err, checker.IsNil, check.Commentf(out))
var configs []swarm.Config
c.Assert(json.Unmarshal([]byte(out), &configs), checker.IsNil)
c.Assert(configs, checker.HasLen, 1)
}
func (s *DockerSwarmSuite) TestConfigInspectMultiple(c *check.C) {
d := s.AddDaemon(c, true, true)
testNames := []string{
"test0",
"test1",
}
for _, n := range testNames {
id := d.CreateConfig(c, swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: n,
},
Data: []byte("TESTINGDATA"),
})
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
config := d.GetConfig(c, id)
c.Assert(config.Spec.Name, checker.Equals, n)
}
args := []string{
"config",
"inspect",
}
args = append(args, testNames...)
out, err := d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
var configs []swarm.Config
c.Assert(json.Unmarshal([]byte(out), &configs), checker.IsNil)
c.Assert(configs, checker.HasLen, 2)
}

View File

@@ -8,8 +8,6 @@ import (
"github.com/go-check/check"
)
// docker cp CONTAINER:PATH LOCALPATH
// Try all of the test cases from the archive package which implements the
// internals of `docker cp` and ensure that the behavior matches when actually
// copying to and from containers.
@@ -20,67 +18,9 @@ import (
// 3. DST parent directory must exist.
// 4. If DST exists as a file, it must not end with a trailing separator.
// First get these easy error cases out of the way.
// Test for error when SRC does not exist.
func (s *DockerSuite) TestCpFromErrSrcNotExists(c *check.C) {
containerID := makeTestContainer(c, testContainerOptions{})
tmpDir := getTestDir(c, "test-cp-from-err-src-not-exists")
defer os.RemoveAll(tmpDir)
err := runDockerCp(c, containerCpPath(containerID, "file1"), tmpDir, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
}
// Test for error when SRC ends in a trailing
// path separator but it exists as a file.
func (s *DockerSuite) TestCpFromErrSrcNotDir(c *check.C) {
testRequires(c, DaemonIsLinux)
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
tmpDir := getTestDir(c, "test-cp-from-err-src-not-dir")
defer os.RemoveAll(tmpDir)
err := runDockerCp(c, containerCpPathTrailingSep(containerID, "file1"), tmpDir, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
}
// Test for error when DST ends in a trailing
// path separator but exists as a file.
func (s *DockerSuite) TestCpFromErrDstNotDir(c *check.C) {
testRequires(c, DaemonIsLinux)
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir")
defer os.RemoveAll(tmpDir)
makeTestContentInDir(c, tmpDir)
// Try with a file source.
srcPath := containerCpPath(containerID, "/file1")
dstPath := cpPathTrailingSep(tmpDir, "file1")
err := runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
// Try with a directory source.
srcPath = containerCpPath(containerID, "/dir1")
err = runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
}
// Check that copying from a container to a local symlink copies to the symlink
// target and does not overwrite the local symlink itself.
// TODO: move to docker/cli and/or integration/container/copy_test.go
func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
testRequires(c, DaemonIsLinux)
containerID := makeTestContainer(c, testContainerOptions{addContent: true})

View File

@@ -2,15 +2,11 @@ package main
import (
"os"
"runtime"
"strings"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
)
// docker cp LOCALPATH CONTAINER:PATH
// Try all of the test cases from the archive package which implements the
// internals of `docker cp` and ensure that the behavior matches when actually
// copying to and from containers.
@@ -21,124 +17,6 @@ import (
// 3. DST parent directory must exist.
// 4. If DST exists as a file, it must not end with a trailing separator.
// First get these easy error cases out of the way.
// Test for error when SRC does not exist.
func (s *DockerSuite) TestCpToErrSrcNotExists(c *check.C) {
containerID := makeTestContainer(c, testContainerOptions{})
tmpDir := getTestDir(c, "test-cp-to-err-src-not-exists")
defer os.RemoveAll(tmpDir)
srcPath := cpPath(tmpDir, "file1")
dstPath := containerCpPath(containerID, "file1")
_, srcStatErr := os.Stat(srcPath)
c.Assert(os.IsNotExist(srcStatErr), checker.True)
err := runDockerCp(c, srcPath, dstPath, nil)
if runtime.GOOS == "windows" {
// Go 1.9+ on Windows returns a different error for `os.Stat()`, see
// https://github.com/golang/go/commit/6144c7270e5812d9de8fb97456ee4e5ae657fcbb#diff-f63e1a4b4377b2fe0b05011db3df9599
//
// Go 1.8: CreateFile C:\not-exist: The system cannot find the file specified.
// Go 1.9: GetFileAttributesEx C:\not-exist: The system cannot find the file specified.
//
// Due to the CLI using a different version than the daemon, comparing the
// error message won't work, so just hard-code the common part here.
//
// TODO this should probably be a test in the CLI repository instead
c.Assert(strings.ToLower(err.Error()), checker.Contains, "cannot find the file specified")
c.Assert(strings.ToLower(err.Error()), checker.Contains, strings.ToLower(tmpDir))
} else {
c.Assert(strings.ToLower(err.Error()), checker.Contains, strings.ToLower(srcStatErr.Error()))
}
}
// Test for error when SRC ends in a trailing
// path separator but it exists as a file.
func (s *DockerSuite) TestCpToErrSrcNotDir(c *check.C) {
containerID := makeTestContainer(c, testContainerOptions{})
tmpDir := getTestDir(c, "test-cp-to-err-src-not-dir")
defer os.RemoveAll(tmpDir)
makeTestContentInDir(c, tmpDir)
srcPath := cpPathTrailingSep(tmpDir, "file1")
dstPath := containerCpPath(containerID, "testDir")
err := runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
}
// Test for error when SRC is a valid file or directory,
// but the DST parent directory does not exist.
func (s *DockerSuite) TestCpToErrDstParentNotExists(c *check.C) {
testRequires(c, DaemonIsLinux)
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
tmpDir := getTestDir(c, "test-cp-to-err-dst-parent-not-exists")
defer os.RemoveAll(tmpDir)
makeTestContentInDir(c, tmpDir)
// Try with a file source.
srcPath := cpPath(tmpDir, "file1")
dstPath := containerCpPath(containerID, "/notExists", "file1")
err := runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
// Try with a directory source.
srcPath = cpPath(tmpDir, "dir1")
err = runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
}
// Test for error when DST ends in a trailing path separator but exists as a
// file. Also test that we cannot overwrite an existing directory with a
// non-directory and cannot overwrite an existing
func (s *DockerSuite) TestCpToErrDstNotDir(c *check.C) {
testRequires(c, DaemonIsLinux)
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
tmpDir := getTestDir(c, "test-cp-to-err-dst-not-dir")
defer os.RemoveAll(tmpDir)
makeTestContentInDir(c, tmpDir)
// Try with a file source.
srcPath := cpPath(tmpDir, "dir1/file1-1")
dstPath := containerCpPathTrailingSep(containerID, "file1")
// The client should encounter an error trying to stat the destination
// and then be unable to copy since the destination is asserted to be a
// directory but does not exist.
err := runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExist error, but got %T: %s", err, err))
// Try with a directory source.
srcPath = cpPath(tmpDir, "dir1")
// The client should encounter an error trying to stat the destination and
// then decide to extract to the parent directory instead with a rebased
// name in the source archive, but this directory would overwrite the
// existing file with the same name.
err = runDockerCp(c, srcPath, dstPath, nil)
c.Assert(err, checker.NotNil)
c.Assert(isCannotOverwriteNonDirWithDir(err), checker.True, check.Commentf("expected CannotOverwriteNonDirWithDir error, but got %T: %s", err, err))
}
// Check that copying from a local path to a symlink in a container copies to
// the symlink target and does not overwrite the container symlink itself.
func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {

View File

@@ -228,18 +228,10 @@ func getTestDir(c *check.C, label string) (tmpDir string) {
return
}
func isCpNotExist(err error) bool {
return strings.Contains(strings.ToLower(err.Error()), "could not find the file")
}
func isCpDirNotExist(err error) bool {
return strings.Contains(err.Error(), archive.ErrDirNotExists.Error())
}
func isCpNotDir(err error) bool {
return strings.Contains(err.Error(), archive.ErrNotDirectory.Error()) || strings.Contains(err.Error(), "filename, directory name, or volume label syntax is incorrect")
}
func isCpCannotCopyDir(err error) bool {
return strings.Contains(err.Error(), archive.ErrCannotCopyDir.Error())
}
@@ -248,10 +240,6 @@ func isCpCannotCopyReadOnly(err error) bool {
return strings.Contains(err.Error(), "marked read-only")
}
func isCannotOverwriteNonDirWithDir(err error) bool {
return strings.Contains(err.Error(), "cannot overwrite non-directory")
}
func fileContentEquals(c *check.C, filename, contents string) (err error) {
c.Logf("checking that file %q contains %q\n", filename, contents)

View File

@@ -49,7 +49,7 @@ func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) {
}
func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, swapMemorySupport)
testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, swapMemorySupport, NotPpc64le)
errChan := make(chan error)
go func() {
@@ -79,7 +79,7 @@ func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
}
func (s *DockerSuite) TestEventsOOMDisableTrue(c *check.C) {
testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, NotArm, swapMemorySupport)
testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, NotArm, swapMemorySupport, NotPpc64le)
errChan := make(chan error)
observer, err := newEventObserver(c)

View File

@@ -9,25 +9,8 @@ import (
"github.com/gotestyourself/gotestyourself/icmd"
)
// export an image and try to import it into a new one
func (s *DockerSuite) TestExportContainerAndImportImage(c *check.C) {
testRequires(c, DaemonIsLinux)
containerID := "testexportcontainerandimportimage"
dockerCmd(c, "run", "--name", containerID, "busybox", "true")
out, _ := dockerCmd(c, "export", containerID)
result := icmd.RunCmd(icmd.Cmd{
Command: []string{dockerBinary, "import", "-", "repo/testexp:v1"},
Stdin: strings.NewReader(out),
})
result.Assert(c, icmd.Success)
cleanedImageID := strings.TrimSpace(result.Combined())
c.Assert(cleanedImageID, checker.Not(checker.Equals), "", check.Commentf("output should have been an image id"))
}
// TODO: Move this test to docker/cli, as it is essentially the same test
// as TestExportContainerAndImportImage except output to a file.
// Used to test output flag in the export command
func (s *DockerSuite) TestExportContainerWithOutputAndImportImage(c *check.C) {
testRequires(c, DaemonIsLinux)

View File

@@ -1541,10 +1541,10 @@ func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) {
dockerCmd(c, "network", "create", "-d", "bridge", "net1")
dockerCmd(c, "network", "create", "-d", "bridge", "net2")
cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top")
cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// ping first container and its alias
@@ -1581,7 +1581,7 @@ func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) {
c.Assert(err, check.IsNil)
// verify the alias option is rejected when running on predefined network
out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox", "top")
out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox:glibc", "top")
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
@@ -1595,10 +1595,10 @@ func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace)
dockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox:glibc", "top")
c.Assert(waitRun("c1.net1"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox:glibc", "top")
c.Assert(waitRun("c2.net1"), check.IsNil)
// ping first container by its unqualified name
@@ -1643,9 +1643,9 @@ func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) {
nr := getNetworkResource(c, "internal")
c.Assert(nr.Internal, checker.True)
dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com")
c.Assert(err, check.NotNil)

View File

@@ -1,87 +0,0 @@
package main
import (
"io/ioutil"
"os"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/cli/build"
"github.com/go-check/check"
)
func (s *DockerSuite) TestRmContainerWithRemovedVolume(c *check.C) {
testRequires(c, SameHostDaemon)
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
tempDir, err := ioutil.TempDir("", "test-rm-container-with-removed-volume-")
if err != nil {
c.Fatalf("failed to create temporary directory: %s", tempDir)
}
defer os.RemoveAll(tempDir)
dockerCmd(c, "run", "--name", "losemyvolumes", "-v", tempDir+":"+prefix+slash+"test", "busybox", "true")
err = os.RemoveAll(tempDir)
c.Assert(err, check.IsNil)
dockerCmd(c, "rm", "-v", "losemyvolumes")
}
func (s *DockerSuite) TestRmContainerWithVolume(c *check.C) {
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
dockerCmd(c, "run", "--name", "foo", "-v", prefix+slash+"srv", "busybox", "true")
dockerCmd(c, "rm", "-v", "foo")
}
func (s *DockerSuite) TestRmContainerRunning(c *check.C) {
createRunningContainer(c, "foo")
res, _, err := dockerCmdWithError("rm", "foo")
c.Assert(err, checker.NotNil, check.Commentf("Expected error, can't rm a running container"))
c.Assert(res, checker.Contains, "cannot remove a running container")
}
func (s *DockerSuite) TestRmContainerForceRemoveRunning(c *check.C) {
createRunningContainer(c, "foo")
// Stop then remove with -f
dockerCmd(c, "rm", "-f", "foo")
}
func (s *DockerSuite) TestRmContainerOrphaning(c *check.C) {
dockerfile1 := `FROM busybox:latest
ENTRYPOINT ["true"]`
img := "test-container-orphaning"
dockerfile2 := `FROM busybox:latest
ENTRYPOINT ["true"]
MAINTAINER Integration Tests`
// build first dockerfile
buildImageSuccessfully(c, img, build.WithDockerfile(dockerfile1))
img1 := getIDByName(c, img)
// run container on first image
dockerCmd(c, "run", img)
// rebuild dockerfile with a small addition at the end
buildImageSuccessfully(c, img, build.WithDockerfile(dockerfile2))
// try to remove the image, should not error out.
out, _, err := dockerCmdWithError("rmi", img)
c.Assert(err, check.IsNil, check.Commentf("Expected to removing the image, but failed: %s", out))
// check if we deleted the first image
out, _ = dockerCmd(c, "images", "-q", "--no-trunc")
c.Assert(out, checker.Contains, img1, check.Commentf("Orphaned container (could not find %q in docker images): %s", img1, out))
}
func (s *DockerSuite) TestRmInvalidContainer(c *check.C) {
out, _, err := dockerCmdWithError("rm", "unknown")
c.Assert(err, checker.NotNil, check.Commentf("Expected error on rm unknown container, got none"))
c.Assert(out, checker.Contains, "No such container")
}
func createRunningContainer(c *check.C, name string) {
runSleepingContainer(c, "-dt", "--name", name)
}

View File

@@ -294,7 +294,7 @@ func (s *DockerSuite) TestUserDefinedNetworkAlias(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
dockerCmd(c, "network", "create", "-d", "bridge", "net1")
cid1, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo1", "--net-alias=foo2", "busybox", "top")
cid1, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo1", "--net-alias=foo2", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
// Check if default short-id alias is added automatically
@@ -302,7 +302,7 @@ func (s *DockerSuite) TestUserDefinedNetworkAlias(c *check.C) {
aliases := inspectField(c, id, "NetworkSettings.Networks.net1.Aliases")
c.Assert(aliases, checker.Contains, stringid.TruncateID(id))
cid2, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
cid2, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// Check if default short-id alias is added automatically

View File

@@ -615,7 +615,7 @@ func (s *DockerSuite) TestRunWithInvalidPathforBlkioDeviceWriteIOps(c *check.C)
}
func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
testRequires(c, memoryLimitSupport, swapMemorySupport)
testRequires(c, memoryLimitSupport, swapMemorySupport, NotPpc64le)
errChan := make(chan error)
go func() {
defer close(errChan)

View File

@@ -1,45 +0,0 @@
// +build !windows
package main
import (
"encoding/json"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
)
func (s *DockerSwarmSuite) TestSecretInspectMultiple(c *check.C) {
d := s.AddDaemon(c, true, true)
testNames := []string{
"test0",
"test1",
}
for _, n := range testNames {
id := d.CreateSecret(c, swarm.SecretSpec{
Annotations: swarm.Annotations{
Name: n,
},
Data: []byte("TESTINGDATA"),
})
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
secret := d.GetSecret(c, id)
c.Assert(secret.Spec.Name, checker.Equals, n)
}
args := []string{
"secret",
"inspect",
}
args = append(args, testNames...)
out, err := d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
var secrets []swarm.Secret
c.Assert(json.Unmarshal([]byte(out), &secrets), checker.IsNil)
c.Assert(secrets, checker.HasLen, 2)
}

View File

@@ -11,41 +11,6 @@ import (
"github.com/go-check/check"
)
func (s *DockerSwarmSuite) TestServiceUpdatePort(c *check.C) {
d := s.AddDaemon(c, true, true)
serviceName := "TestServiceUpdatePort"
serviceArgs := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "-p", "8080:8081", defaultSleepImage}, sleepCommandForDaemonPlatform()...)
// Create a service with a port mapping of 8080:8081.
out, err := d.Cmd(serviceArgs...)
c.Assert(err, checker.IsNil)
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
// Update the service: changed the port mapping from 8080:8081 to 8082:8083.
_, err = d.Cmd("service", "update", "--detach", "--publish-add", "8082:8083", "--publish-rm", "8081", serviceName)
c.Assert(err, checker.IsNil)
// Inspect the service and verify port mapping
expected := []swarm.PortConfig{
{
Protocol: "tcp",
PublishedPort: 8082,
TargetPort: 8083,
PublishMode: "ingress",
},
}
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.EndpointSpec.Ports }}", serviceName)
c.Assert(err, checker.IsNil)
var portConfig []swarm.PortConfig
if err := json.Unmarshal([]byte(out), &portConfig); err != nil {
c.Fatalf("invalid JSON in inspect result: %v (%s)", err, out)
}
c.Assert(portConfig, checker.DeepEquals, expected)
}
func (s *DockerSwarmSuite) TestServiceUpdateLabel(c *check.C) {
d := s.AddDaemon(c, true, true)
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name=test", "busybox", "top")

View File

@@ -345,13 +345,13 @@ func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
_, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox", "top")
_, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox:glibc", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
_, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox", "top")
_, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox:glibc", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
_, err = d.Cmd("run", "-d", "--net=foo", "--net-alias=third-alias", "busybox", "top")
_, err = d.Cmd("run", "-d", "--net=foo", "--net-alias=third-alias", "busybox:glibc", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
// ping first container and its alias, also ping third and anonymous container by its alias

View File

@@ -143,8 +143,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
// Ensure the network was created
assertNwIsAvailable(c, "dualstackbridge")
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "--ip", "172.28.100.20", "--ip6", "2001:db8:abc2::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=second", "--ip", "172.28.100.21", "--ip6", "2001:db8:abc2::21", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "--ip", "172.28.100.20", "--ip6", "2001:db8:abc2::20", "busybox:glibc", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=second", "--ip", "172.28.100.21", "--ip6", "2001:db8:abc2::21", "busybox:glibc", "top")
// Inspect and store the v4 address from specified container on the network dualstackbridge
ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.IPAddress")
@@ -160,8 +160,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
c.Assert(err, check.IsNil)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=third", "--ip", "172.28.102.20", "--ip6", "2001:db8:abc4::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=fourth", "--ip", "172.28.102.21", "--ip6", "2001:db8:abc4::21", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=third", "--ip", "172.28.102.20", "--ip6", "2001:db8:abc4::20", "busybox:glibc", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=fourth", "--ip", "172.28.102.21", "--ip6", "2001:db8:abc4::21", "busybox:glibc", "top")
// Inspect and store the v4 address from specified container on the network dualstackbridge
ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPAddress")
@@ -198,8 +198,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
// Ensure the network was created
assertNwIsAvailable(c, "dualstackl2")
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.200.0/24 and 2001:db8:abc8::/64
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=first", "--ip", "172.28.200.20", "--ip6", "2001:db8:abc8::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "--ip", "172.28.200.21", "--ip6", "2001:db8:abc8::21", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=first", "--ip", "172.28.200.20", "--ip6", "2001:db8:abc8::20", "busybox:glibc", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "--ip", "172.28.200.21", "--ip6", "2001:db8:abc8::21", "busybox:glibc", "top")
// Inspect and store the v4 address from specified container on the network dualstackl2
ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPAddress")
@@ -214,8 +214,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
c.Assert(err, check.IsNil)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.202.0/24 and 2001:db8:abc6::/64
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=third", "--ip", "172.28.202.20", "--ip6", "2001:db8:abc6::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=fourth", "--ip", "172.28.202.21", "--ip6", "2001:db8:abc6::21", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=third", "--ip", "172.28.202.20", "--ip6", "2001:db8:abc6::20", "busybox:glibc", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=fourth", "--ip", "172.28.202.21", "--ip6", "2001:db8:abc6::21", "busybox:glibc", "top")
// Inspect and store the v4 address from specified container on the network dualstackl2
ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPAddress")
@@ -253,8 +253,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
assertNwIsAvailable(c, "dualstackl3")
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.10.0/24 and 2001:db8:abc9::/64
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=first", "--ip", "172.28.10.20", "--ip6", "2001:db8:abc9::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=second", "--ip", "172.28.10.21", "--ip6", "2001:db8:abc9::21", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=first", "--ip", "172.28.10.20", "--ip6", "2001:db8:abc9::20", "busybox:glibc", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=second", "--ip", "172.28.10.21", "--ip6", "2001:db8:abc9::21", "busybox:glibc", "top")
// Inspect and store the v4 address from specified container on the network dualstackl3
ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.IPAddress")
@@ -269,8 +269,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
c.Assert(err, check.IsNil)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.12.0/24 and 2001:db8:abc7::/64
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "--ip", "172.28.12.20", "--ip6", "2001:db8:abc7::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=fourth", "--ip", "172.28.12.21", "--ip6", "2001:db8:abc7::21", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "--ip", "172.28.12.20", "--ip6", "2001:db8:abc7::20", "busybox:glibc", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=fourth", "--ip", "172.28.12.21", "--ip6", "2001:db8:abc7::21", "busybox:glibc", "top")
// Inspect and store the v4 address from specified container on the network dualstackl3
ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPAddress")
@@ -356,9 +356,9 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
assertNwIsAvailable(c, "dm-nil-parent")
// start two containers on the same subnet
dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=first", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=second", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// intra-network communications should succeed
@@ -375,9 +375,9 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
c.Assert(nr.Internal, checker.True)
// start two containers on the same subnet
cli.DockerCmd(c, "run", "-d", "--net=dm-internal", "--name=first", "busybox", "top")
cli.DockerCmd(c, "run", "-d", "--net=dm-internal", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
cli.DockerCmd(c, "run", "-d", "--net=dm-internal", "--name=second", "busybox", "top")
cli.DockerCmd(c, "run", "-d", "--net=dm-internal", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// access outside of the network should fail
@@ -395,9 +395,9 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
assertNwIsAvailable(c, "di-nil-parent")
// start two containers on the same subnet
dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=first", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=second", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// intra-network communications should succeed
@@ -414,9 +414,9 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
c.Assert(nr.Internal, checker.True)
// start two containers on the same subnet
cli.DockerCmd(c, "run", "-d", "--net=di-internal", "--name=first", "busybox", "top")
cli.DockerCmd(c, "run", "-d", "--net=di-internal", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
cli.DockerCmd(c, "run", "-d", "--net=di-internal", "--name=second", "busybox", "top")
cli.DockerCmd(c, "run", "-d", "--net=di-internal", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// access outside of the network should fail
@@ -434,9 +434,9 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
assertNwIsAvailable(c, "di-nil-parent-l3")
// start two containers on separate subnets
dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-nil-parent-l3", "--name=first", "busybox", "top")
dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-nil-parent-l3", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-nil-parent-l3", "--name=second", "busybox", "top")
dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-nil-parent-l3", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// intra-network communications should succeed
@@ -454,9 +454,9 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
c.Assert(nr.Internal, checker.True)
// start two containers on separate subnets
cli.DockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-internal-l3", "--name=first", "busybox", "top")
cli.DockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-internal-l3", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
cli.DockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-internal-l3", "--name=second", "busybox", "top")
cli.DockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-internal-l3", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// access outside of the network should fail
@@ -496,9 +496,9 @@ func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
assertNwIsAvailable(c, netName)
// start containers on 802.1q tagged '-o parent' sub-interface
dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=first", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=first", "busybox:glibc", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=second", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=second", "busybox:glibc", "top")
c.Assert(waitRun("second"), check.IsNil)
// verify containers can communicate
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")

View File

@@ -37,9 +37,6 @@ func FrozenImagesLinux(client client.APIClient, images ...string) error {
if img == "hello-world:frozen" {
srcName = "hello-world:latest"
}
if img == "busybox:1.27-glibc" {
img = "busybox:latest"
}
loadImages = append(loadImages, struct{ srcName, destName string }{
srcName: srcName,
destName: img,

View File

@@ -1,7 +1,8 @@
package config
package config // import "github.com/docker/docker/integration/config"
import (
"bytes"
"encoding/json"
"sort"
"testing"
"time"
@@ -327,3 +328,27 @@ func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool)
time.Sleep(100 * time.Millisecond)
}
}
func TestConfigInspect(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
testName := t.Name()
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
insp, body, err := client.ConfigInspectWithRaw(ctx, configID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Name, testName)
var config swarmtypes.Config
err = json.Unmarshal(body, &config)
require.NoError(t, err)
assert.Equal(t, config, insp)
}

View File

@@ -1,4 +1,4 @@
package config
package config // import "github.com/docker/docker/integration/config"
import (
"fmt"

View File

@@ -0,0 +1,65 @@
package container // import "github.com/docker/docker/integration/container"
import (
"context"
"fmt"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/require"
)
func TestCopyFromContainerPathDoesNotExist(t *testing.T) {
defer setupTest(t)()
ctx := context.Background()
apiclient := testEnv.APIClient()
cid := container.Create(t, ctx, apiclient)
_, _, err := apiclient.CopyFromContainer(ctx, cid, "/dne")
require.True(t, client.IsErrNotFound(err))
expected := fmt.Sprintf("No such container:path: %s:%s", cid, "/dne")
testutil.ErrorContains(t, err, expected)
}
func TestCopyFromContainerPathIsNotDir(t *testing.T) {
defer setupTest(t)()
skip.If(t, testEnv.OSType == "windows")
ctx := context.Background()
apiclient := testEnv.APIClient()
cid := container.Create(t, ctx, apiclient)
_, _, err := apiclient.CopyFromContainer(ctx, cid, "/etc/passwd/")
require.Contains(t, err.Error(), "not a directory")
}
func TestCopyToContainerPathDoesNotExist(t *testing.T) {
defer setupTest(t)()
skip.If(t, testEnv.OSType == "windows")
ctx := context.Background()
apiclient := testEnv.APIClient()
cid := container.Create(t, ctx, apiclient)
err := apiclient.CopyToContainer(ctx, cid, "/dne", nil, types.CopyToContainerOptions{})
require.True(t, client.IsErrNotFound(err))
expected := fmt.Sprintf("No such container:path: %s:%s", cid, "/dne")
testutil.ErrorContains(t, err, expected)
}
func TestCopyToContainerPathIsNotDir(t *testing.T) {
defer setupTest(t)()
skip.If(t, testEnv.OSType == "windows")
ctx := context.Background()
apiclient := testEnv.APIClient()
cid := container.Create(t, ctx, apiclient)
err := apiclient.CopyToContainer(ctx, cid, "/etc/passwd/", nil, types.CopyToContainerOptions{})
require.Contains(t, err.Error(), "not a directory")
}

View File

@@ -1,4 +1,4 @@
package container
package container // import "github.com/docker/docker/integration/container"
import (
"context"
@@ -9,8 +9,9 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration/internal/container"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"golang.org/x/sys/unix"
)
@@ -26,6 +27,7 @@ import (
// the container process, then start dockerd back up and attempt to start the
// container again.
func TestContainerStartOnDaemonRestart(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
t.Parallel()
d := daemon.New(t, "", "dockerd", daemon.Config{})
@@ -36,22 +38,14 @@ func TestContainerStartOnDaemonRestart(t *testing.T) {
assert.NoError(t, err, "error creating client")
ctx := context.Background()
c, err := client.ContainerCreate(ctx,
&container.Config{
Image: "busybox",
Cmd: []string{"top"},
},
nil,
nil,
"",
)
assert.NoError(t, err, "error creating test container")
defer client.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true})
err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
cID := container.Create(t, ctx, client)
defer client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
assert.NoError(t, err, "error starting test container")
inspect, err := client.ContainerInspect(ctx, c.ID)
inspect, err := client.ContainerInspect(ctx, cID)
assert.NoError(t, err, "error getting inspect data")
ppid := getContainerdShimPid(t, inspect)
@@ -67,7 +61,7 @@ func TestContainerStartOnDaemonRestart(t *testing.T) {
d.Start(t, "--iptables=false")
err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
assert.NoError(t, err, "failed to start test container")
}

View File

@@ -10,13 +10,11 @@ import (
"github.com/docker/docker/integration/internal/request"
"github.com/docker/docker/pkg/archive"
"github.com/gotestyourself/gotestyourself/poll"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ensure that an added file shows up in docker diff
func TestDiffFilenameShownInOutput(t *testing.T) {
func TestDiff(t *testing.T) {
defer setupTest(t)()
client := request.NewAPIClient(t)
ctx := context.Background()
@@ -27,72 +25,19 @@ func TestDiffFilenameShownInOutput(t *testing.T) {
// it will take a few seconds to exit. Also there's no way in Windows to
// differentiate between an Add or a Modify, and all files are under
// a "Files/" prefix.
lookingFor := containertypes.ContainerChangeResponseItem{Kind: archive.ChangeAdd, Path: "/foo/bar"}
expected := []containertypes.ContainerChangeResponseItem{
{Kind: archive.ChangeAdd, Path: "/foo"},
{Kind: archive.ChangeAdd, Path: "/foo/bar"},
}
if testEnv.OSType == "windows" {
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(60*time.Second))
lookingFor = containertypes.ContainerChangeResponseItem{Kind: archive.ChangeModify, Path: "Files/foo/bar"}
expected = []containertypes.ContainerChangeResponseItem{
{Kind: archive.ChangeModify, Path: "Files/foo"},
{Kind: archive.ChangeModify, Path: "Files/foo/bar"},
}
}
items, err := client.ContainerDiff(ctx, cID)
require.NoError(t, err)
assert.Contains(t, items, lookingFor)
}
// test to ensure GH #3840 doesn't occur any more
func TestDiffEnsureInitLayerFilesAreIgnored(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
client := request.NewAPIClient(t)
ctx := context.Background()
// this is a list of files which shouldn't show up in `docker diff`
initLayerFiles := []string{"/etc/resolv.conf", "/etc/hostname", "/etc/hosts", "/.dockerenv"}
containerCount := 5
// we might not run into this problem from the first run, so start a few containers
for i := 0; i < containerCount; i++ {
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", `echo foo > /root/bar`))
items, err := client.ContainerDiff(ctx, cID)
require.NoError(t, err)
for _, item := range items {
assert.NotContains(t, initLayerFiles, item.Path)
}
}
}
func TestDiffEnsureDefaultDevs(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
client := request.NewAPIClient(t)
ctx := context.Background()
cID := container.Run(t, ctx, client, container.WithCmd("sleep", "0"))
items, err := client.ContainerDiff(ctx, cID)
require.NoError(t, err)
expected := []containertypes.ContainerChangeResponseItem{
{Kind: archive.ChangeModify, Path: "/dev"},
{Kind: archive.ChangeAdd, Path: "/dev/full"}, // busybox
{Kind: archive.ChangeModify, Path: "/dev/ptmx"}, // libcontainer
{Kind: archive.ChangeAdd, Path: "/dev/mqueue"},
{Kind: archive.ChangeAdd, Path: "/dev/kmsg"},
{Kind: archive.ChangeAdd, Path: "/dev/fd"},
{Kind: archive.ChangeAdd, Path: "/dev/ptmx"},
{Kind: archive.ChangeAdd, Path: "/dev/null"},
{Kind: archive.ChangeAdd, Path: "/dev/random"},
{Kind: archive.ChangeAdd, Path: "/dev/stdout"},
{Kind: archive.ChangeAdd, Path: "/dev/stderr"},
{Kind: archive.ChangeAdd, Path: "/dev/tty1"},
{Kind: archive.ChangeAdd, Path: "/dev/stdin"},
{Kind: archive.ChangeAdd, Path: "/dev/tty"},
{Kind: archive.ChangeAdd, Path: "/dev/urandom"},
}
for _, item := range items {
assert.Contains(t, expected, item)
}
assert.Equal(t, expected, items)
}

View File

@@ -0,0 +1,53 @@
package container // import "github.com/docker/docker/integration/container"
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/integration/internal/request"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/gotestyourself/gotestyourself/poll"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// export an image and try to import it into a new one
func TestExportContainerAndImportImage(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
client := request.NewAPIClient(t)
ctx := context.Background()
cID := container.Run(t, ctx, client, container.WithCmd("true"))
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
reference := "repo/testexp:v1"
exportResp, err := client.ContainerExport(ctx, cID)
require.NoError(t, err)
importResp, err := client.ImageImport(ctx, types.ImageImportSource{
Source: exportResp,
SourceName: "-",
}, reference, types.ImageImportOptions{})
require.NoError(t, err)
// If the import is successfully, then the message output should contain
// the image ID and match with the output from `docker images`.
dec := json.NewDecoder(importResp)
var jm jsonmessage.JSONMessage
err = dec.Decode(&jm)
require.NoError(t, err)
images, err := client.ImageList(ctx, types.ImageListOptions{
Filters: filters.NewArgs(filters.Arg("reference", reference)),
})
require.NoError(t, err)
assert.Equal(t, jm.Status, images[0].ID)
}

View File

@@ -40,9 +40,9 @@ func TestInspectCpusetInConfigPre120(t *testing.T) {
require.NoError(t, err, "unable to unmarshal body for version 1.19: %s", err)
config, ok := inspectJSON["Config"]
assert.Equal(t, ok, true, "Unable to find 'Config'")
assert.Equal(t, true, ok, "Unable to find 'Config'")
cfg := config.(map[string]interface{})
_, ok = cfg["Cpuset"]
assert.Equal(t, ok, true, "API version 1.19 expected to include Cpuset in 'Config'")
assert.Equal(t, true, ok, "API version 1.19 expected to include Cpuset in 'Config'")
}

View File

@@ -1,4 +1,4 @@
package container
package container // import "github.com/docker/docker/integration/container"
import (
"context"
@@ -155,8 +155,7 @@ func TestInspectOomKilledTrue(t *testing.T) {
ctx := context.Background()
client := request.NewAPIClient(t)
name := "testoomkilled"
cID := container.Run(t, ctx, client, container.WithName(name), container.WithCmd("sh", "-c", "x=a; while true; do x=$x$x$x$x; done"), func(c *container.TestContainerConfig) {
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "x=a; while true; do x=$x$x$x$x; done"), func(c *container.TestContainerConfig) {
c.HostConfig.Resources.Memory = 32 * 1024 * 1024
})
@@ -164,7 +163,7 @@ func TestInspectOomKilledTrue(t *testing.T) {
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.State.OOMKilled, true)
assert.Equal(t, true, inspect.State.OOMKilled)
}
func TestInspectOomKilledFalse(t *testing.T) {
@@ -174,12 +173,11 @@ func TestInspectOomKilledFalse(t *testing.T) {
ctx := context.Background()
client := request.NewAPIClient(t)
name := "testoomkilled"
cID := container.Run(t, ctx, client, container.WithName(name), container.WithCmd("sh", "-c", "echo hello world"))
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "echo hello world"))
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.State.OOMKilled, false)
assert.Equal(t, false, inspect.State.OOMKilled)
}

View File

@@ -20,7 +20,7 @@ import (
)
func TestLinksEtcHostsContentMatch(t *testing.T) {
skip.If(t, !testEnv.IsLocalDaemon())
skip.If(t, testEnv.IsRemoteDaemon())
hosts, err := ioutil.ReadFile("/etc/hosts")
skip.If(t, os.IsNotExist(err))

View File

@@ -1,4 +1,4 @@
package container
package container // import "github.com/docker/docker/integration/container"
import (
"context"
@@ -20,7 +20,6 @@ func TestLogsFollowTailEmpty(t *testing.T) {
ctx := context.Background()
id := container.Run(t, ctx, client, container.WithCmd("sleep", "100000"))
defer client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true})
logs, err := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"})
if logs != nil {

View File

@@ -23,6 +23,7 @@ import (
)
func TestContainerShmNoLeak(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
t.Parallel()
d := daemon.New(t, "docker", "dockerd", daemon.Config{})
client, err := d.NewClient()
@@ -94,7 +95,7 @@ func TestContainerShmNoLeak(t *testing.T) {
func TestContainerNetworkMountsNoChown(t *testing.T) {
// chown only applies to Linux bind mounted volumes; must be same host to verify
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.IsLocalDaemon())
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
defer setupTest(t)()

View File

@@ -1,4 +1,4 @@
package container
package container // import "github.com/docker/docker/integration/container"
import (
"bytes"
@@ -22,7 +22,7 @@ import (
)
func TestNetworkNat(t *testing.T) {
skip.If(t, !testEnv.IsLocalDaemon())
skip.If(t, testEnv.IsRemoteDaemon())
defer setupTest(t)()
@@ -36,11 +36,11 @@ func TestNetworkNat(t *testing.T) {
data, err := ioutil.ReadAll(conn)
require.NoError(t, err)
assert.Equal(t, strings.TrimSpace(string(data)), msg)
assert.Equal(t, msg, strings.TrimSpace(string(data)))
}
func TestNetworkLocalhostTCPNat(t *testing.T) {
skip.If(t, !testEnv.IsLocalDaemon())
skip.If(t, testEnv.IsRemoteDaemon())
defer setupTest(t)()
@@ -53,11 +53,11 @@ func TestNetworkLocalhostTCPNat(t *testing.T) {
data, err := ioutil.ReadAll(conn)
require.NoError(t, err)
assert.Equal(t, strings.TrimSpace(string(data)), msg)
assert.Equal(t, msg, strings.TrimSpace(string(data)))
}
func TestNetworkLoopbackNat(t *testing.T) {
skip.If(t, !testEnv.IsLocalDaemon())
skip.If(t, testEnv.IsRemoteDaemon())
msg := "it works"
startServerContainer(t, msg, 8080)
@@ -81,7 +81,7 @@ func TestNetworkLoopbackNat(t *testing.T) {
_, err = io.Copy(&b, body)
require.NoError(t, err)
assert.Equal(t, strings.TrimSpace(b.String()), msg)
assert.Equal(t, msg, strings.TrimSpace(b.String()))
}
func startServerContainer(t *testing.T, msg string, port int) string {
@@ -109,7 +109,7 @@ func getExternalAddress(t *testing.T) net.IP {
ifaceAddrs, err := iface.Addrs()
require.NoError(t, err)
assert.NotEqual(t, len(ifaceAddrs), 0)
assert.NotEqual(t, 0, len(ifaceAddrs))
ifaceIP, _, err := net.ParseCIDR(ifaceAddrs[0].String())
require.NoError(t, err)

View File

@@ -25,20 +25,19 @@ func TestPause(t *testing.T) {
client := request.NewAPIClient(t)
ctx := context.Background()
name := "testeventpause"
cID := container.Run(t, ctx, client, container.WithName(name))
cID := container.Run(t, ctx, client)
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
since := request.DaemonUnixTime(ctx, t, client, testEnv)
err := client.ContainerPause(ctx, name)
err := client.ContainerPause(ctx, cID)
require.NoError(t, err)
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.State.Paused, true)
assert.Equal(t, true, inspect.State.Paused)
err = client.ContainerUnpause(ctx, name)
err = client.ContainerUnpause(ctx, cID)
require.NoError(t, err)
until := request.DaemonUnixTime(ctx, t, client, testEnv)
@@ -46,9 +45,9 @@ func TestPause(t *testing.T) {
messages, errs := client.Events(ctx, types.EventsOptions{
Since: since,
Until: until,
Filters: filters.NewArgs(filters.Arg("container", name)),
Filters: filters.NewArgs(filters.Arg("container", cID)),
})
assert.Equal(t, getEventActions(t, messages, errs), []string{"pause", "unpause"})
assert.Equal(t, []string{"pause", "unpause"}, getEventActions(t, messages, errs))
}
func TestPauseFailsOnWindowsServerContainers(t *testing.T) {
@@ -89,7 +88,7 @@ func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan e
for {
select {
case err := <-errs:
assert.Equal(t, err == nil || err == io.EOF, true)
assert.True(t, err == nil || err == io.EOF)
return actions
case e := <-messages:
actions = append(actions, e.Status)

View File

@@ -5,9 +5,8 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/integration/internal/request"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -18,23 +17,9 @@ func TestPsFilter(t *testing.T) {
client := request.NewAPIClient(t)
ctx := context.Background()
createContainerForFilter := func(ctx context.Context, name string) string {
body, err := client.ContainerCreate(ctx,
&container.Config{
Cmd: []string{"top"},
Image: "busybox",
},
&container.HostConfig{},
&network.NetworkingConfig{},
name,
)
require.NoError(t, err)
return body.ID
}
prev := createContainerForFilter(ctx, "prev")
createContainerForFilter(ctx, "top")
next := createContainerForFilter(ctx, "next")
prev := container.Create(t, ctx, client, container.WithName("prev"))
container.Create(t, ctx, client, container.WithName("top"))
next := container.Create(t, ctx, client, container.WithName("next"))
containerIDs := func(containers []types.Container) []string {
entries := []string{}

View File

@@ -0,0 +1,113 @@
package container // import "github.com/docker/docker/integration/container"
import (
"context"
"os"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/integration/internal/request"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/gotestyourself/gotestyourself/poll"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
if testEnv.OSType == "windows" {
return "c:", `\`
}
return "", "/"
}
// Test case for #5244: `docker rm` fails if bind dir doesn't exist anymore
func TestRemoveContainerWithRemovedVolume(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
tempDir := fs.NewDir(t, "test-rm-container-with-removed-volume", fs.WithMode(0755))
defer tempDir.Remove()
cID := container.Run(t, ctx, client, container.WithCmd("true"), container.WithBind(tempDir.Path(), prefix+slash+"test"))
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
err := os.RemoveAll(tempDir.Path())
require.NoError(t, err)
err = client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
RemoveVolumes: true,
})
require.NoError(t, err)
_, _, err = client.ContainerInspectWithRaw(ctx, cID, true)
testutil.ErrorContains(t, err, "No such container")
}
// Test case for #2099/#2125
func TestRemoveContainerWithVolume(t *testing.T) {
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
cID := container.Run(t, ctx, client, container.WithCmd("true"), container.WithVolume(prefix+slash+"srv"))
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
insp, _, err := client.ContainerInspectWithRaw(ctx, cID, true)
require.NoError(t, err)
assert.Equal(t, 1, len(insp.Mounts))
volName := insp.Mounts[0].Name
err = client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
RemoveVolumes: true,
})
require.NoError(t, err)
volumes, err := client.VolumeList(ctx, filters.NewArgs(filters.Arg("name", volName)))
require.NoError(t, err)
assert.Equal(t, 0, len(volumes.Volumes))
}
func TestRemoveContainerRunning(t *testing.T) {
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
cID := container.Run(t, ctx, client)
err := client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{})
testutil.ErrorContains(t, err, "cannot remove a running container")
}
func TestRemoveContainerForceRemoveRunning(t *testing.T) {
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
cID := container.Run(t, ctx, client)
err := client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
Force: true,
})
require.NoError(t, err)
}
func TestRemoveInvalidContainer(t *testing.T) {
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
err := client.ContainerRemove(ctx, "unknown", types.ContainerRemoveOptions{})
testutil.ErrorContains(t, err, "No such container")
}

View File

@@ -55,7 +55,7 @@ func TestRenameStoppedContainer(t *testing.T) {
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.Name, "/"+oldName)
assert.Equal(t, "/"+oldName, inspect.Name)
newName := "new_name" + stringid.GenerateNonCryptoID()
err = client.ContainerRename(ctx, oldName, newName)
@@ -63,7 +63,7 @@ func TestRenameStoppedContainer(t *testing.T) {
inspect, err = client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.Name, "/"+newName)
assert.Equal(t, "/"+newName, inspect.Name)
}
func TestRenameRunningContainerAndReuse(t *testing.T) {
@@ -81,7 +81,7 @@ func TestRenameRunningContainerAndReuse(t *testing.T) {
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.Name, "/"+newName)
assert.Equal(t, "/"+newName, inspect.Name)
_, err = client.ContainerInspect(ctx, oldName)
testutil.ErrorContains(t, err, "No such container: "+oldName)
@@ -91,7 +91,7 @@ func TestRenameRunningContainerAndReuse(t *testing.T) {
inspect, err = client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.Name, "/"+oldName)
assert.Equal(t, "/"+oldName, inspect.Name)
}
func TestRenameInvalidName(t *testing.T) {
@@ -108,7 +108,7 @@ func TestRenameInvalidName(t *testing.T) {
inspect, err := client.ContainerInspect(ctx, oldName)
require.NoError(t, err)
assert.Equal(t, inspect.ID, cID)
assert.Equal(t, cID, inspect.ID)
}
// Test case for GitHub issue 22466
@@ -133,6 +133,10 @@ func TestRenameAnonymousContainer(t *testing.T) {
})
err = client.ContainerRename(ctx, cID, "container1")
require.NoError(t, err)
// Stop/Start the container to get registered
// FIXME(vdemeester) this is a really weird behavior as it fails otherwise
err = client.ContainerStop(ctx, "container1", nil)
require.NoError(t, err)
err = client.ContainerStart(ctx, "container1", types.ContainerStartOptions{})
require.NoError(t, err)
@@ -152,7 +156,7 @@ func TestRenameAnonymousContainer(t *testing.T) {
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.State.ExitCode, 0)
assert.Equal(t, 0, inspect.State.ExitCode, "container %s exited with the wrong exitcode: %+v", cID, inspect)
}
// TODO: should be a unit test
@@ -175,7 +179,7 @@ func TestRenameContainerWithSameName(t *testing.T) {
// of the linked container should be updated so that the other
// container could still reference to the container that is renamed.
func TestRenameContainerWithLinkedContainer(t *testing.T) {
skip.If(t, !testEnv.IsLocalDaemon())
skip.If(t, testEnv.IsRemoteDaemon())
defer setupTest(t)()
ctx := context.Background()
@@ -192,5 +196,5 @@ func TestRenameContainerWithLinkedContainer(t *testing.T) {
inspect, err := client.ContainerInspect(ctx, "app2/mysql")
require.NoError(t, err)
assert.Equal(t, inspect.ID, db1ID)
assert.Equal(t, db1ID, inspect.ID)
}

View File

@@ -44,7 +44,7 @@ func TestResizeWithInvalidSize(t *testing.T) {
endpoint := "/containers/" + cID + "/resize?h=foo&w=bar"
res, _, err := req.Post(endpoint)
require.NoError(t, err)
assert.Equal(t, res.StatusCode, http.StatusBadRequest)
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
}
func TestResizeWhenContainerNotStarted(t *testing.T) {

Some files were not shown because too many files have changed in this diff Show More