mirror of
https://github.com/containers/skopeo.git
synced 2026-02-02 15:29:34 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9b2a8a7ef | ||
|
|
b37a981500 | ||
|
|
a500e22104 |
@@ -19,7 +19,7 @@ const (
|
||||
// identify working containers.
|
||||
Package = "buildah"
|
||||
// Version for the Package
|
||||
Version = "0.2"
|
||||
Version = "0.3"
|
||||
// The value we use to identify what type of information, currently a
|
||||
// serialized Builder structure, we are using as per-container state.
|
||||
// This should only be changed when we make incompatible changes to
|
||||
|
||||
6
run.go
6
run.go
@@ -153,12 +153,6 @@ func (b *Builder) Run(command []string, options RunOptions) error {
|
||||
}()
|
||||
g := generate.New()
|
||||
|
||||
if b.OS() != "" {
|
||||
g.SetPlatformOS(b.OS())
|
||||
}
|
||||
if b.Architecture() != "" {
|
||||
g.SetPlatformArch(b.Architecture())
|
||||
}
|
||||
for _, envSpec := range append(b.Env(), options.Env...) {
|
||||
env := strings.SplitN(envSpec, "=", 2)
|
||||
if len(env) > 1 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
github.com/BurntSushi/toml master
|
||||
github.com/Nvveen/Gotty master
|
||||
github.com/blang/semver master
|
||||
github.com/containers/image 23bddaa64cc6bf3f3077cda0dbf1cdd7007434df
|
||||
github.com/containers/image c2a797dfe5bb4a9dd7f48332ce40c6223ffba492
|
||||
github.com/containers/storage 105f7c77aef0c797429e41552743bf5b03b63263
|
||||
github.com/docker/distribution master
|
||||
github.com/docker/docker 0f9ec7e47072b0c2e954b5b821bde5c1fe81bfa7
|
||||
@@ -22,10 +22,10 @@ github.com/mistifyio/go-zfs master
|
||||
github.com/moby/moby 0f9ec7e47072b0c2e954b5b821bde5c1fe81bfa7
|
||||
github.com/mtrmac/gpgme master
|
||||
github.com/opencontainers/go-digest aa2ec055abd10d26d539eb630a92241b781ce4bc
|
||||
github.com/opencontainers/image-spec v1.0.0-rc6
|
||||
github.com/opencontainers/image-spec v1.0.0
|
||||
github.com/opencontainers/runc master
|
||||
github.com/opencontainers/runtime-spec v1.0.0-rc5
|
||||
github.com/opencontainers/runtime-tools 8addcc695096a0fc61010af8766952546bba7cd0
|
||||
github.com/opencontainers/runtime-spec v1.0.0
|
||||
github.com/opencontainers/runtime-tools 2d270b8764c02228eeb13e36f076f5ce6f2e3591
|
||||
github.com/opencontainers/selinux ba1aefe8057f1d0cfb8e88d0ec1dc85925ef987d
|
||||
github.com/openshift/imagebuilder master
|
||||
github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460
|
||||
|
||||
49
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
49
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
@@ -308,31 +308,36 @@ func (c *dockerClient) setupRequestAuth(req *http.Request) error {
|
||||
if len(c.challenges) == 0 {
|
||||
return nil
|
||||
}
|
||||
// assume just one...
|
||||
challenge := c.challenges[0]
|
||||
switch challenge.Scheme {
|
||||
case "basic":
|
||||
req.SetBasicAuth(c.username, c.password)
|
||||
return nil
|
||||
case "bearer":
|
||||
if c.token == nil || time.Now().After(c.tokenExpiration) {
|
||||
realm, ok := challenge.Parameters["realm"]
|
||||
if !ok {
|
||||
return errors.Errorf("missing realm in bearer auth challenge")
|
||||
schemeNames := make([]string, 0, len(c.challenges))
|
||||
for _, challenge := range c.challenges {
|
||||
schemeNames = append(schemeNames, challenge.Scheme)
|
||||
switch challenge.Scheme {
|
||||
case "basic":
|
||||
req.SetBasicAuth(c.username, c.password)
|
||||
return nil
|
||||
case "bearer":
|
||||
if c.token == nil || time.Now().After(c.tokenExpiration) {
|
||||
realm, ok := challenge.Parameters["realm"]
|
||||
if !ok {
|
||||
return errors.Errorf("missing realm in bearer auth challenge")
|
||||
}
|
||||
service, _ := challenge.Parameters["service"] // Will be "" if not present
|
||||
scope := fmt.Sprintf("repository:%s:%s", c.scope.remoteName, c.scope.actions)
|
||||
token, err := c.getBearerToken(realm, service, scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.token = token
|
||||
c.tokenExpiration = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
|
||||
}
|
||||
service, _ := challenge.Parameters["service"] // Will be "" if not present
|
||||
scope := fmt.Sprintf("repository:%s:%s", c.scope.remoteName, c.scope.actions)
|
||||
token, err := c.getBearerToken(realm, service, scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.token = token
|
||||
c.tokenExpiration = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token.Token))
|
||||
return nil
|
||||
default:
|
||||
logrus.Debugf("no handler for %s authentication", challenge.Scheme)
|
||||
}
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token.Token))
|
||||
return nil
|
||||
}
|
||||
return errors.Errorf("no handler for %s authentication", challenge.Scheme)
|
||||
logrus.Infof("None of the challenges sent by server (%s) are supported, trying an unauthenticated request anyway", strings.Join(schemeNames, ", "))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *dockerClient) getBearerToken(realm, service, scope string) (*bearerToken, error) {
|
||||
|
||||
2
vendor/github.com/containers/image/docker/tarfile/dest.go
generated
vendored
2
vendor/github.com/containers/image/docker/tarfile/dest.go
generated
vendored
@@ -181,7 +181,7 @@ func (d *Destination) PutManifest(m []byte) error {
|
||||
layerPaths = append(layerPaths, l.Digest.String())
|
||||
}
|
||||
|
||||
items := []manifestItem{{
|
||||
items := []ManifestItem{{
|
||||
Config: man.Config.Digest.String(),
|
||||
RepoTags: []string{d.repoTag},
|
||||
Layers: layerPaths,
|
||||
|
||||
31
vendor/github.com/containers/image/docker/tarfile/src.go
generated
vendored
31
vendor/github.com/containers/image/docker/tarfile/src.go
generated
vendored
@@ -20,7 +20,7 @@ import (
|
||||
type Source struct {
|
||||
tarPath string
|
||||
// The following data is only available after ensureCachedDataIsPresent() succeeds
|
||||
tarManifest *manifestItem // nil if not available yet.
|
||||
tarManifest *ManifestItem // nil if not available yet.
|
||||
configBytes []byte
|
||||
configDigest digest.Digest
|
||||
orderedDiffIDList []diffID
|
||||
@@ -145,23 +145,28 @@ func (s *Source) ensureCachedDataIsPresent() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check to make sure length is 1
|
||||
if len(tarManifest) != 1 {
|
||||
return errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(tarManifest))
|
||||
}
|
||||
|
||||
// Read and parse config.
|
||||
configBytes, err := s.readTarComponent(tarManifest.Config)
|
||||
configBytes, err := s.readTarComponent(tarManifest[0].Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var parsedConfig image // Most fields ommitted, we only care about layer DiffIDs.
|
||||
if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
|
||||
return errors.Wrapf(err, "Error decoding tar config %s", tarManifest.Config)
|
||||
return errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
|
||||
}
|
||||
|
||||
knownLayers, err := s.prepareLayerData(tarManifest, &parsedConfig)
|
||||
knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Success; commit.
|
||||
s.tarManifest = tarManifest
|
||||
s.tarManifest = &tarManifest[0]
|
||||
s.configBytes = configBytes
|
||||
s.configDigest = digest.FromBytes(configBytes)
|
||||
s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
|
||||
@@ -170,23 +175,25 @@ func (s *Source) ensureCachedDataIsPresent() error {
|
||||
}
|
||||
|
||||
// loadTarManifest loads and decodes the manifest.json.
|
||||
func (s *Source) loadTarManifest() (*manifestItem, error) {
|
||||
func (s *Source) loadTarManifest() ([]ManifestItem, error) {
|
||||
// FIXME? Do we need to deal with the legacy format?
|
||||
bytes, err := s.readTarComponent(manifestFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var items []manifestItem
|
||||
var items []ManifestItem
|
||||
if err := json.Unmarshal(bytes, &items); err != nil {
|
||||
return nil, errors.Wrap(err, "Error decoding tar manifest.json")
|
||||
}
|
||||
if len(items) != 1 {
|
||||
return nil, errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(items))
|
||||
}
|
||||
return &items[0], nil
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (s *Source) prepareLayerData(tarManifest *manifestItem, parsedConfig *image) (map[diffID]*layerInfo, error) {
|
||||
// LoadTarManifest loads and decodes the manifest.json
|
||||
func (s *Source) LoadTarManifest() ([]ManifestItem, error) {
|
||||
return s.loadTarManifest()
|
||||
}
|
||||
|
||||
func (s *Source) prepareLayerData(tarManifest *ManifestItem, parsedConfig *image) (map[diffID]*layerInfo, error) {
|
||||
// Collect layer data available in manifest and config.
|
||||
if len(tarManifest.Layers) != len(parsedConfig.RootFS.DiffIDs) {
|
||||
return nil, errors.Errorf("Inconsistent layer count: %d in manifest, %d in config", len(tarManifest.Layers), len(parsedConfig.RootFS.DiffIDs))
|
||||
|
||||
3
vendor/github.com/containers/image/docker/tarfile/types.go
generated
vendored
3
vendor/github.com/containers/image/docker/tarfile/types.go
generated
vendored
@@ -13,7 +13,8 @@ const (
|
||||
// legacyRepositoriesFileName = "repositories"
|
||||
)
|
||||
|
||||
type manifestItem struct {
|
||||
// ManifestItem is an element of the array stored in the top-level manifest.json file.
|
||||
type ManifestItem struct {
|
||||
Config string
|
||||
RepoTags []string
|
||||
Layers []string
|
||||
|
||||
2
vendor/github.com/containers/image/image/docker_list.go
generated
vendored
2
vendor/github.com/containers/image/image/docker_list.go
generated
vendored
@@ -16,7 +16,7 @@ type platformSpec struct {
|
||||
OSVersion string `json:"os.version,omitempty"`
|
||||
OSFeatures []string `json:"os.features,omitempty"`
|
||||
Variant string `json:"variant,omitempty"`
|
||||
Features []string `json:"features,omitempty"`
|
||||
Features []string `json:"features,omitempty"` // removed in OCI
|
||||
}
|
||||
|
||||
// A manifestDescriptor references a platform-specific manifest.
|
||||
|
||||
15
vendor/github.com/containers/image/image/docker_schema2.go
generated
vendored
15
vendor/github.com/containers/image/image/docker_schema2.go
generated
vendored
@@ -183,6 +183,7 @@ func (m *manifestSchema2) UpdatedImage(options types.ManifestUpdateOptions) (typ
|
||||
}
|
||||
copy.LayersDescriptors = make([]descriptor, len(options.LayerInfos))
|
||||
for i, info := range options.LayerInfos {
|
||||
copy.LayersDescriptors[i].MediaType = m.LayersDescriptors[i].MediaType
|
||||
copy.LayersDescriptors[i].Digest = info.Digest
|
||||
copy.LayersDescriptors[i].Size = info.Size
|
||||
copy.LayersDescriptors[i].URLs = info.URLs
|
||||
@@ -213,15 +214,17 @@ func (m *manifestSchema2) convertToManifestOCI1() (types.Image, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := descriptor{
|
||||
MediaType: imgspecv1.MediaTypeImageConfig,
|
||||
Size: int64(len(configOCIBytes)),
|
||||
Digest: digest.FromBytes(configOCIBytes),
|
||||
config := descriptorOCI1{
|
||||
descriptor: descriptor{
|
||||
MediaType: imgspecv1.MediaTypeImageConfig,
|
||||
Size: int64(len(configOCIBytes)),
|
||||
Digest: digest.FromBytes(configOCIBytes),
|
||||
},
|
||||
}
|
||||
|
||||
layers := make([]descriptor, len(m.LayersDescriptors))
|
||||
layers := make([]descriptorOCI1, len(m.LayersDescriptors))
|
||||
for idx := range layers {
|
||||
layers[idx] = m.LayersDescriptors[idx]
|
||||
layers[idx] = descriptorOCI1{descriptor: m.LayersDescriptors[idx]}
|
||||
if m.LayersDescriptors[idx].MediaType == manifest.DockerV2Schema2ForeignLayerMediaType {
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerNonDistributable
|
||||
} else {
|
||||
|
||||
19
vendor/github.com/containers/image/image/oci.go
generated
vendored
19
vendor/github.com/containers/image/image/oci.go
generated
vendored
@@ -12,12 +12,18 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type descriptorOCI1 struct {
|
||||
descriptor
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
type manifestOCI1 struct {
|
||||
src types.ImageSource // May be nil if configBlob is not nil
|
||||
configBlob []byte // If set, corresponds to contents of ConfigDescriptor.
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
ConfigDescriptor descriptor `json:"config"`
|
||||
LayersDescriptors []descriptor `json:"layers"`
|
||||
ConfigDescriptor descriptorOCI1 `json:"config"`
|
||||
LayersDescriptors []descriptorOCI1 `json:"layers"`
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
func manifestOCI1FromManifest(src types.ImageSource, manifest []byte) (genericManifest, error) {
|
||||
@@ -29,7 +35,7 @@ func manifestOCI1FromManifest(src types.ImageSource, manifest []byte) (genericMa
|
||||
}
|
||||
|
||||
// manifestOCI1FromComponents builds a new manifestOCI1 from the supplied data:
|
||||
func manifestOCI1FromComponents(config descriptor, src types.ImageSource, configBlob []byte, layers []descriptor) genericManifest {
|
||||
func manifestOCI1FromComponents(config descriptorOCI1, src types.ImageSource, configBlob []byte, layers []descriptorOCI1) genericManifest {
|
||||
return &manifestOCI1{
|
||||
src: src,
|
||||
configBlob: configBlob,
|
||||
@@ -148,8 +154,9 @@ func (m *manifestOCI1) UpdatedImage(options types.ManifestUpdateOptions) (types.
|
||||
if len(copy.LayersDescriptors) != len(options.LayerInfos) {
|
||||
return nil, errors.Errorf("Error preparing updated manifest: layer count changed from %d to %d", len(copy.LayersDescriptors), len(options.LayerInfos))
|
||||
}
|
||||
copy.LayersDescriptors = make([]descriptor, len(options.LayerInfos))
|
||||
copy.LayersDescriptors = make([]descriptorOCI1, len(options.LayerInfos))
|
||||
for i, info := range options.LayerInfos {
|
||||
copy.LayersDescriptors[i].MediaType = m.LayersDescriptors[i].MediaType
|
||||
copy.LayersDescriptors[i].Digest = info.Digest
|
||||
copy.LayersDescriptors[i].Size = info.Size
|
||||
}
|
||||
@@ -169,7 +176,7 @@ func (m *manifestOCI1) UpdatedImage(options types.ManifestUpdateOptions) (types.
|
||||
|
||||
func (m *manifestOCI1) convertToManifestSchema2() (types.Image, error) {
|
||||
// Create a copy of the descriptor.
|
||||
config := m.ConfigDescriptor
|
||||
config := m.ConfigDescriptor.descriptor
|
||||
|
||||
// The only difference between OCI and DockerSchema2 is the mediatypes. The
|
||||
// media type of the manifest is handled by manifestSchema2FromComponents.
|
||||
@@ -177,7 +184,7 @@ func (m *manifestOCI1) convertToManifestSchema2() (types.Image, error) {
|
||||
|
||||
layers := make([]descriptor, len(m.LayersDescriptors))
|
||||
for idx := range layers {
|
||||
layers[idx] = m.LayersDescriptors[idx]
|
||||
layers[idx] = m.LayersDescriptors[idx].descriptor
|
||||
layers[idx].MediaType = manifest.DockerV2Schema2LayerMediaType
|
||||
}
|
||||
|
||||
|
||||
12
vendor/github.com/containers/image/storage/storage_image.go
generated
vendored
12
vendor/github.com/containers/image/storage/storage_image.go
generated
vendored
@@ -174,11 +174,11 @@ func (s *storageImageDestination) putBlob(stream io.Reader, blobinfo types.BlobI
|
||||
}
|
||||
// Attempt to create the identified layer and import its contents.
|
||||
layer, uncompressedSize, err := s.imageRef.transport.store.PutLayer(id, parentLayer, nil, "", true, multi)
|
||||
if err != nil && err != storage.ErrDuplicateID {
|
||||
if err != nil && errors.Cause(err) != storage.ErrDuplicateID {
|
||||
logrus.Debugf("error importing layer blob %q as %q: %v", blobinfo.Digest, id, err)
|
||||
return errorBlobInfo, err
|
||||
}
|
||||
if err == storage.ErrDuplicateID {
|
||||
if errors.Cause(err) == storage.ErrDuplicateID {
|
||||
// We specified an ID, and there's already a layer with
|
||||
// the same ID. Drain the input so that we can look at
|
||||
// its length and digest.
|
||||
@@ -291,7 +291,7 @@ func (s *storageImageDestination) PutBlob(stream io.Reader, blobinfo types.BlobI
|
||||
// it returns a non-nil error only on an unexpected failure.
|
||||
func (s *storageImageDestination) HasBlob(blobinfo types.BlobInfo) (bool, int64, error) {
|
||||
if blobinfo.Digest == "" {
|
||||
return false, -1, errors.Errorf(`"Can not check for a blob with unknown digest`)
|
||||
return false, -1, errors.Errorf(`Can not check for a blob with unknown digest`)
|
||||
}
|
||||
for _, blob := range s.BlobList {
|
||||
if blob.Digest == blobinfo.Digest {
|
||||
@@ -331,7 +331,7 @@ func (s *storageImageDestination) Commit() error {
|
||||
}
|
||||
img, err := s.imageRef.transport.store.CreateImage(s.ID, nil, lastLayer, "", nil)
|
||||
if err != nil {
|
||||
if err != storage.ErrDuplicateID {
|
||||
if errors.Cause(err) != storage.ErrDuplicateID {
|
||||
logrus.Debugf("error creating image: %q", err)
|
||||
return errors.Wrapf(err, "error creating image %q", s.ID)
|
||||
}
|
||||
@@ -340,8 +340,8 @@ func (s *storageImageDestination) Commit() error {
|
||||
return errors.Wrapf(err, "error reading image %q", s.ID)
|
||||
}
|
||||
if img.TopLayer != lastLayer {
|
||||
logrus.Debugf("error creating image: image with ID %q exists, but uses different layers", err)
|
||||
return errors.Wrapf(err, "image with ID %q already exists, but uses a different top layer", s.ID)
|
||||
logrus.Debugf("error creating image: image with ID %q exists, but uses different layers", s.ID)
|
||||
return errors.Wrapf(storage.ErrDuplicateID, "image with ID %q already exists, but uses a different top layer", s.ID)
|
||||
}
|
||||
logrus.Debugf("reusing image ID %q", img.ID)
|
||||
} else {
|
||||
|
||||
20
vendor/github.com/containers/image/storage/storage_reference.go
generated
vendored
20
vendor/github.com/containers/image/storage/storage_reference.go
generated
vendored
@@ -70,7 +70,9 @@ func (s *storageReference) resolveImage() (*storage.Image, error) {
|
||||
// to build this reference object.
|
||||
func (s storageReference) Transport() types.ImageTransport {
|
||||
return &storageTransport{
|
||||
store: s.transport.store,
|
||||
store: s.transport.store,
|
||||
defaultUIDMap: s.transport.defaultUIDMap,
|
||||
defaultGIDMap: s.transport.defaultGIDMap,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +85,12 @@ func (s storageReference) DockerReference() reference.Named {
|
||||
// disambiguate between images which may be present in multiple stores and
|
||||
// share only their names.
|
||||
func (s storageReference) StringWithinTransport() string {
|
||||
storeSpec := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "]"
|
||||
optionsList := ""
|
||||
options := s.transport.store.GraphOptions()
|
||||
if len(options) > 0 {
|
||||
optionsList = ":" + strings.Join(options, ",")
|
||||
}
|
||||
storeSpec := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "+" + s.transport.store.RunRoot() + optionsList + "]"
|
||||
if s.name == nil {
|
||||
return storeSpec + "@" + s.id
|
||||
}
|
||||
@@ -94,7 +101,14 @@ func (s storageReference) StringWithinTransport() string {
|
||||
}
|
||||
|
||||
func (s storageReference) PolicyConfigurationIdentity() string {
|
||||
return s.StringWithinTransport()
|
||||
storeSpec := "[" + s.transport.store.GraphDriverName() + "@" + s.transport.store.GraphRoot() + "]"
|
||||
if s.name == nil {
|
||||
return storeSpec + "@" + s.id
|
||||
}
|
||||
if s.id == "" {
|
||||
return storeSpec + s.reference
|
||||
}
|
||||
return storeSpec + s.reference + "@" + s.id
|
||||
}
|
||||
|
||||
// Also accept policy that's tied to the combination of the graph root and
|
||||
|
||||
145
vendor/github.com/containers/image/storage/storage_transport.go
generated
vendored
145
vendor/github.com/containers/image/storage/storage_transport.go
generated
vendored
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/containers/image/transports"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ddigest "github.com/opencontainers/go-digest"
|
||||
)
|
||||
@@ -46,10 +47,20 @@ type StoreTransport interface {
|
||||
// ParseStoreReference parses a reference, overriding any store
|
||||
// specification that it may contain.
|
||||
ParseStoreReference(store storage.Store, reference string) (*storageReference, error)
|
||||
// SetDefaultUIDMap sets the default UID map to use when opening stores.
|
||||
SetDefaultUIDMap(idmap []idtools.IDMap)
|
||||
// SetDefaultGIDMap sets the default GID map to use when opening stores.
|
||||
SetDefaultGIDMap(idmap []idtools.IDMap)
|
||||
// DefaultUIDMap returns the default UID map used when opening stores.
|
||||
DefaultUIDMap() []idtools.IDMap
|
||||
// DefaultGIDMap returns the default GID map used when opening stores.
|
||||
DefaultGIDMap() []idtools.IDMap
|
||||
}
|
||||
|
||||
type storageTransport struct {
|
||||
store storage.Store
|
||||
store storage.Store
|
||||
defaultUIDMap []idtools.IDMap
|
||||
defaultGIDMap []idtools.IDMap
|
||||
}
|
||||
|
||||
func (s *storageTransport) Name() string {
|
||||
@@ -66,6 +77,26 @@ func (s *storageTransport) SetStore(store storage.Store) {
|
||||
s.store = store
|
||||
}
|
||||
|
||||
// SetDefaultUIDMap sets the default UID map to use when opening stores.
|
||||
func (s *storageTransport) SetDefaultUIDMap(idmap []idtools.IDMap) {
|
||||
s.defaultUIDMap = idmap
|
||||
}
|
||||
|
||||
// SetDefaultGIDMap sets the default GID map to use when opening stores.
|
||||
func (s *storageTransport) SetDefaultGIDMap(idmap []idtools.IDMap) {
|
||||
s.defaultGIDMap = idmap
|
||||
}
|
||||
|
||||
// DefaultUIDMap returns the default UID map used when opening stores.
|
||||
func (s *storageTransport) DefaultUIDMap() []idtools.IDMap {
|
||||
return s.defaultUIDMap
|
||||
}
|
||||
|
||||
// DefaultGIDMap returns the default GID map used when opening stores.
|
||||
func (s *storageTransport) DefaultGIDMap() []idtools.IDMap {
|
||||
return s.defaultGIDMap
|
||||
}
|
||||
|
||||
// ParseStoreReference takes a name or an ID, tries to figure out which it is
|
||||
// relative to the given store, and returns it in a reference object.
|
||||
func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (*storageReference, error) {
|
||||
@@ -110,7 +141,12 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
|
||||
// recognize.
|
||||
return nil, ErrInvalidReference
|
||||
}
|
||||
storeSpec := "[" + store.GraphDriverName() + "@" + store.GraphRoot() + "]"
|
||||
optionsList := ""
|
||||
options := store.GraphOptions()
|
||||
if len(options) > 0 {
|
||||
optionsList = ":" + strings.Join(options, ",")
|
||||
}
|
||||
storeSpec := "[" + store.GraphDriverName() + "@" + store.GraphRoot() + "+" + store.RunRoot() + optionsList + "]"
|
||||
id := ""
|
||||
if sum.Validate() == nil {
|
||||
id = sum.Hex()
|
||||
@@ -127,14 +163,17 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
|
||||
} else {
|
||||
logrus.Debugf("parsed reference into %q", storeSpec+refname+"@"+id)
|
||||
}
|
||||
return newReference(storageTransport{store: store}, refname, id, name), nil
|
||||
return newReference(storageTransport{store: store, defaultUIDMap: s.defaultUIDMap, defaultGIDMap: s.defaultGIDMap}, refname, id, name), nil
|
||||
}
|
||||
|
||||
func (s *storageTransport) GetStore() (storage.Store, error) {
|
||||
// Return the transport's previously-set store. If we don't have one
|
||||
// of those, initialize one now.
|
||||
if s.store == nil {
|
||||
store, err := storage.GetStore(storage.DefaultStoreOptions)
|
||||
options := storage.DefaultStoreOptions
|
||||
options.UIDMap = s.defaultUIDMap
|
||||
options.GIDMap = s.defaultGIDMap
|
||||
store, err := storage.GetStore(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -145,15 +184,11 @@ func (s *storageTransport) GetStore() (storage.Store, error) {
|
||||
|
||||
// ParseReference takes a name and/or an ID ("_name_"/"@_id_"/"_name_@_id_"),
|
||||
// possibly prefixed with a store specifier in the form "[_graphroot_]" or
|
||||
// "[_driver_@_graphroot_]", tries to figure out which it is, and returns it in
|
||||
// a reference object. If the _graphroot_ is a location other than the default,
|
||||
// it needs to have been previously opened using storage.GetStore(), so that it
|
||||
// can figure out which run root goes with the graph root.
|
||||
// "[_driver_@_graphroot_]" or "[_driver_@_graphroot_+_runroot_]" or
|
||||
// "[_driver_@_graphroot_:_options_]" or "[_driver_@_graphroot_+_runroot_:_options_]",
|
||||
// tries to figure out which it is, and returns it in a reference object.
|
||||
func (s *storageTransport) ParseReference(reference string) (types.ImageReference, error) {
|
||||
store, err := s.GetStore()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var store storage.Store
|
||||
// Check if there's a store location prefix. If there is, then it
|
||||
// needs to match a store that was previously initialized using
|
||||
// storage.GetStore(), or be enough to let the storage library fill out
|
||||
@@ -165,37 +200,65 @@ func (s *storageTransport) ParseReference(reference string) (types.ImageReferenc
|
||||
}
|
||||
storeSpec := reference[1:closeIndex]
|
||||
reference = reference[closeIndex+1:]
|
||||
storeInfo := strings.SplitN(storeSpec, "@", 2)
|
||||
if len(storeInfo) == 1 && storeInfo[0] != "" {
|
||||
// One component: the graph root.
|
||||
if !filepath.IsAbs(storeInfo[0]) {
|
||||
return nil, ErrPathNotAbsolute
|
||||
// Peel off a "driver@" from the start.
|
||||
driverInfo := ""
|
||||
driverSplit := strings.SplitN(storeSpec, "@", 2)
|
||||
if len(driverSplit) != 2 {
|
||||
if storeSpec == "" {
|
||||
return nil, ErrInvalidReference
|
||||
}
|
||||
store2, err := storage.GetStore(storage.StoreOptions{
|
||||
GraphRoot: storeInfo[0],
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
store = store2
|
||||
} else if len(storeInfo) == 2 && storeInfo[0] != "" && storeInfo[1] != "" {
|
||||
// Two components: the driver type and the graph root.
|
||||
if !filepath.IsAbs(storeInfo[1]) {
|
||||
return nil, ErrPathNotAbsolute
|
||||
}
|
||||
store2, err := storage.GetStore(storage.StoreOptions{
|
||||
GraphDriverName: storeInfo[0],
|
||||
GraphRoot: storeInfo[1],
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
store = store2
|
||||
} else {
|
||||
// Anything else: store specified in a form we don't
|
||||
// recognize.
|
||||
return nil, ErrInvalidReference
|
||||
driverInfo = driverSplit[0]
|
||||
if driverInfo == "" {
|
||||
return nil, ErrInvalidReference
|
||||
}
|
||||
storeSpec = driverSplit[1]
|
||||
if storeSpec == "" {
|
||||
return nil, ErrInvalidReference
|
||||
}
|
||||
}
|
||||
// Peel off a ":options" from the end.
|
||||
var options []string
|
||||
optionsSplit := strings.SplitN(storeSpec, ":", 2)
|
||||
if len(optionsSplit) == 2 {
|
||||
options = strings.Split(optionsSplit[1], ",")
|
||||
storeSpec = optionsSplit[0]
|
||||
}
|
||||
// Peel off a "+runroot" from the new end.
|
||||
runRootInfo := ""
|
||||
runRootSplit := strings.SplitN(storeSpec, "+", 2)
|
||||
if len(runRootSplit) == 2 {
|
||||
runRootInfo = runRootSplit[1]
|
||||
storeSpec = runRootSplit[0]
|
||||
}
|
||||
// The rest is our graph root.
|
||||
rootInfo := storeSpec
|
||||
// Check that any paths are absolute paths.
|
||||
if rootInfo != "" && !filepath.IsAbs(rootInfo) {
|
||||
return nil, ErrPathNotAbsolute
|
||||
}
|
||||
if runRootInfo != "" && !filepath.IsAbs(runRootInfo) {
|
||||
return nil, ErrPathNotAbsolute
|
||||
}
|
||||
store2, err := storage.GetStore(storage.StoreOptions{
|
||||
GraphDriverName: driverInfo,
|
||||
GraphRoot: rootInfo,
|
||||
RunRoot: runRootInfo,
|
||||
GraphDriverOptions: options,
|
||||
UIDMap: s.defaultUIDMap,
|
||||
GIDMap: s.defaultGIDMap,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
store = store2
|
||||
} else {
|
||||
// We didn't have a store spec, so use the default.
|
||||
store2, err := s.GetStore()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
store = store2
|
||||
}
|
||||
return s.ParseStoreReference(store, reference)
|
||||
}
|
||||
@@ -250,7 +313,7 @@ func (s storageTransport) ValidatePolicyConfigurationScope(scope string) error {
|
||||
return ErrPathNotAbsolute
|
||||
}
|
||||
} else {
|
||||
// Anything else: store specified in a form we don't
|
||||
// Anything else: scope specified in a form we don't
|
||||
// recognize.
|
||||
return ErrInvalidReference
|
||||
}
|
||||
|
||||
167
vendor/github.com/opencontainers/image-spec/README.md
generated
vendored
Normal file
167
vendor/github.com/opencontainers/image-spec/README.md
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
# OCI Image Format Specification
|
||||
<div>
|
||||
<a href="https://travis-ci.org/opencontainers/image-spec">
|
||||
<img src="https://travis-ci.org/opencontainers/image-spec.svg?branch=master"></img>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
The OCI Image Format project creates and maintains the software shipping container image format spec (OCI Image Format).
|
||||
|
||||
**[The specification can be found here](spec.md).**
|
||||
|
||||
This repository also provides [Go types](specs-go), [intra-blob validation tooling, and JSON Schema](schema).
|
||||
The Go types and validation should be compatible with the current Go release; earlier Go releases are not supported.
|
||||
|
||||
Additional documentation about how this group operates:
|
||||
|
||||
- [Code of Conduct](https://github.com/opencontainers/tob/blob/d2f9d68c1332870e40693fe077d311e0742bc73d/code-of-conduct.md)
|
||||
- [Roadmap](#roadmap)
|
||||
- [Releases](RELEASES.md)
|
||||
- [Project Documentation](project.md)
|
||||
|
||||
The _optional_ and _base_ layers of all OCI projects are tracked in the [OCI Scope Table](https://www.opencontainers.org/about/oci-scope-table).
|
||||
|
||||
## Running an OCI Image
|
||||
|
||||
The OCI Image Format partner project is the [OCI Runtime Spec project](https://github.com/opencontainers/runtime-spec).
|
||||
The Runtime Specification outlines how to run a "[filesystem bundle](https://github.com/opencontainers/runtime-spec/blob/master/bundle.md)" that is unpacked on disk.
|
||||
At a high-level an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle.
|
||||
At this point the OCI Runtime Bundle would be run by an OCI Runtime.
|
||||
|
||||
This entire workflow supports the UX that users have come to expect from container engines like Docker and rkt: primarily, the ability to run an image with no additional arguments:
|
||||
|
||||
* docker run example.com/org/app:v1.0.0
|
||||
* rkt run example.com/org/app,version=v1.0.0
|
||||
|
||||
To support this UX the OCI Image Format contains sufficient information to launch the application on the target platform (e.g. command, arguments, environment variables, etc).
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Why doesn't this project mention distribution?**
|
||||
|
||||
A: Distribution, for example using HTTP as both Docker v2.2 and AppC do today, is currently out of scope on the [OCI Scope Table](https://www.opencontainers.org/about/oci-scope-table).
|
||||
There has been [some discussion on the TOB mailing list](https://groups.google.com/a/opencontainers.org/d/msg/tob/A3JnmI-D-6Y/tLuptPDHAgAJ) to make distribution an optional layer, but this topic is a work in progress.
|
||||
|
||||
**Q: What happens to AppC or Docker Image Formats?**
|
||||
|
||||
A: Existing formats can continue to be a proving ground for technologies, as needed.
|
||||
The OCI Image Format project strives to provide a dependable open specification that can be shared between different tools and be evolved for years or decades of compatibility; as the deb and rpm format have.
|
||||
|
||||
Find more [FAQ on the OCI site](https://www.opencontainers.org/faq).
|
||||
|
||||
## Roadmap
|
||||
|
||||
The [GitHub milestones](https://github.com/opencontainers/image-spec/milestones) lay out the path to the OCI v1.0.0 release in late 2016.
|
||||
|
||||
# Contributing
|
||||
|
||||
Development happens on GitHub for the spec.
|
||||
Issues are used for bugs and actionable items and longer discussions can happen on the [mailing list](#mailing-list).
|
||||
|
||||
The specification and code is licensed under the Apache 2.0 license found in the `LICENSE` file of this repository.
|
||||
|
||||
## Discuss your design
|
||||
|
||||
The project welcomes submissions, but please let everyone know what you are working on.
|
||||
|
||||
Before undertaking a nontrivial change to this specification, send mail to the [mailing list](#mailing-list) to discuss what you plan to do.
|
||||
This gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits.
|
||||
It also guarantees that the design is sound before code is written; a GitHub pull-request is not the place for high-level discussions.
|
||||
|
||||
Typos and grammatical errors can go straight to a pull-request.
|
||||
When in doubt, start on the [mailing-list](#mailing-list).
|
||||
|
||||
## Weekly Call
|
||||
|
||||
The contributors and maintainers of all OCI projects have a weekly meeting Wednesdays at 2:00 PM (USA Pacific).
|
||||
Everyone is welcome to participate via [UberConference web][UberConference] or audio-only: +1-415-968-0849 (no PIN needed).
|
||||
An initial agenda will be posted to the [mailing list](#mailing-list) earlier in the week, and everyone is welcome to propose additional topics or suggest other agenda alterations there.
|
||||
Minutes are posted to the [mailing list](#mailing-list) and minutes from past calls are archived [here][minutes].
|
||||
|
||||
## Mailing List
|
||||
|
||||
You can subscribe and join the mailing list on [Google Groups](https://groups.google.com/a/opencontainers.org/forum/#!forum/dev).
|
||||
|
||||
## IRC
|
||||
|
||||
OCI discussion happens on #opencontainers on Freenode ([logs][irc-logs]).
|
||||
|
||||
## Markdown style
|
||||
|
||||
To keep consistency throughout the Markdown files in the Open Container spec all files should be formatted one sentence per line.
|
||||
This fixes two things: it makes diffing easier with git and it resolves fights about line wrapping length.
|
||||
For example, this paragraph will span three lines in the Markdown source.
|
||||
|
||||
## Git commit
|
||||
|
||||
### Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch.
|
||||
The rules are pretty simple: if you can certify the below (from [developercertificate.org](http://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe@gmail.com>
|
||||
|
||||
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
You can add the sign off when creating the git commit via `git commit -s`.
|
||||
|
||||
### Commit Style
|
||||
|
||||
Simple house-keeping for clean git history.
|
||||
Read more on [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/) or the Discussion section of [`git-commit(1)`](http://git-scm.com/docs/git-commit).
|
||||
|
||||
1. Separate the subject from body with a blank line
|
||||
2. Limit the subject line to 50 characters
|
||||
3. Capitalize the subject line
|
||||
4. Do not end the subject line with a period
|
||||
5. Use the imperative mood in the subject line
|
||||
6. Wrap the body at 72 characters
|
||||
7. Use the body to explain what and why vs. how
|
||||
* If there was important/useful/essential conversation or information, copy or include a reference
|
||||
8. When possible, one keyword to scope the change in the subject (i.e. "README: ...", "runtime: ...")
|
||||
|
||||
|
||||
[UberConference]: https://www.uberconference.com/opencontainers
|
||||
[irc-logs]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/
|
||||
[minutes]: http://ircbot.wl.linuxfoundation.org/meetings/opencontainers/
|
||||
56
vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
generated
vendored
Normal file
56
vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2016 The Linux Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1
|
||||
|
||||
const (
|
||||
// AnnotationCreated is the annotation key for the date and time on which the image was built (date-time string as defined by RFC 3339).
|
||||
AnnotationCreated = "org.opencontainers.image.created"
|
||||
|
||||
// AnnotationAuthors is the annotation key for the contact details of the people or organization responsible for the image (freeform string).
|
||||
AnnotationAuthors = "org.opencontainers.image.authors"
|
||||
|
||||
// AnnotationURL is the annotation key for the URL to find more information on the image.
|
||||
AnnotationURL = "org.opencontainers.image.url"
|
||||
|
||||
// AnnotationDocumentation is the annotation key for the URL to get documentation on the image.
|
||||
AnnotationDocumentation = "org.opencontainers.image.documentation"
|
||||
|
||||
// AnnotationSource is the annotation key for the URL to get source code for building the image.
|
||||
AnnotationSource = "org.opencontainers.image.source"
|
||||
|
||||
// AnnotationVersion is the annotation key for the version of the packaged software.
|
||||
// The version MAY match a label or tag in the source code repository.
|
||||
// The version MAY be Semantic versioning-compatible.
|
||||
AnnotationVersion = "org.opencontainers.image.version"
|
||||
|
||||
// AnnotationRevision is the annotation key for the source control revision identifier for the packaged software.
|
||||
AnnotationRevision = "org.opencontainers.image.revision"
|
||||
|
||||
// AnnotationVendor is the annotation key for the name of the distributing entity, organization or individual.
|
||||
AnnotationVendor = "org.opencontainers.image.vendor"
|
||||
|
||||
// AnnotationLicenses is the annotation key for the license(s) under which contained software is distributed as an SPDX License Expression.
|
||||
AnnotationLicenses = "org.opencontainers.image.licenses"
|
||||
|
||||
// AnnotationRefName is the annotation key for the name of the reference for a target.
|
||||
// SHOULD only be considered valid when on descriptors on `index.json` within image layout.
|
||||
AnnotationRefName = "org.opencontainers.image.ref.name"
|
||||
|
||||
// AnnotationTitle is the annotation key for the human-readable title of the image.
|
||||
AnnotationTitle = "org.opencontainers.image.title"
|
||||
|
||||
// AnnotationDescription is the annotation key for the human-readable description of the software packaged in the image.
|
||||
AnnotationDescription = "org.opencontainers.image.description"
|
||||
)
|
||||
2
vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go
generated
vendored
2
vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go
generated
vendored
@@ -37,7 +37,7 @@ type ImageConfig struct {
|
||||
// Cmd defines the default arguments to the entrypoint of the container.
|
||||
Cmd []string `json:"Cmd,omitempty"`
|
||||
|
||||
// Volumes is a set of directories which should be created as data volumes in a container running this image.
|
||||
// Volumes is a set of directories describing where the process is likely write data specific to a container instance.
|
||||
Volumes map[string]struct{} `json:"Volumes,omitempty"`
|
||||
|
||||
// WorkingDir sets the current working directory of the entrypoint process in the container.
|
||||
|
||||
2
vendor/github.com/opencontainers/image-spec/specs-go/version.go
generated
vendored
2
vendor/github.com/opencontainers/image-spec/specs-go/version.go
generated
vendored
@@ -25,7 +25,7 @@ const (
|
||||
VersionPatch = 0
|
||||
|
||||
// VersionDev indicates development branch. Releases will be empty string.
|
||||
VersionDev = "-rc6-dev"
|
||||
VersionDev = ""
|
||||
)
|
||||
|
||||
// Version is the specification version that the package types support.
|
||||
|
||||
158
vendor/github.com/opencontainers/runtime-spec/README.md
generated
vendored
Normal file
158
vendor/github.com/opencontainers/runtime-spec/README.md
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
# Open Container Initiative Runtime Specification
|
||||
|
||||
The [Open Container Initiative][oci] develops specifications for standards on Operating System process and application containers.
|
||||
|
||||
The specification can be found [here](spec.md).
|
||||
|
||||
## Table of Contents
|
||||
|
||||
Additional documentation about how this group operates:
|
||||
|
||||
- [Code of Conduct][code-of-conduct]
|
||||
- [Style and Conventions](style.md)
|
||||
- [Implementations](implementations.md)
|
||||
- [Releases](RELEASES.md)
|
||||
- [project](project.md)
|
||||
- [charter][charter]
|
||||
|
||||
## Use Cases
|
||||
|
||||
To provide context for users the following section gives example use cases for each part of the spec.
|
||||
|
||||
### Application Bundle Builders
|
||||
|
||||
Application bundle builders can create a [bundle](bundle.md) directory that includes all of the files required for launching an application as a container.
|
||||
The bundle contains an OCI [configuration file](config.md) where the builder can specify host-independent details such as [which executable to launch](config.md#process) and host-specific settings such as [mount](config.md#mounts) locations, [hook](config.md#hooks) paths, Linux [namespaces](config-linux.md#namespaces) and [cgroups](config-linux.md#control-groups).
|
||||
Because the configuration includes host-specific settings, application bundle directories copied between two hosts may require configuration adjustments.
|
||||
|
||||
### Hook Developers
|
||||
|
||||
[Hook](config.md#hooks) developers can extend the functionality of an OCI-compliant runtime by hooking into a container's lifecycle with an external application.
|
||||
Example use cases include sophisticated network configuration, volume garbage collection, etc.
|
||||
|
||||
### Runtime Developers
|
||||
|
||||
Runtime developers can build runtime implementations that run OCI-compliant bundles and container configuration, containing low-level OS and host-specific details, on a particular platform.
|
||||
|
||||
## Contributing
|
||||
|
||||
Development happens on GitHub for the spec.
|
||||
Issues are used for bugs and actionable items and longer discussions can happen on the [mailing list](#mailing-list).
|
||||
|
||||
The specification and code is licensed under the Apache 2.0 license found in the [LICENSE](./LICENSE) file.
|
||||
|
||||
### Discuss your design
|
||||
|
||||
The project welcomes submissions, but please let everyone know what you are working on.
|
||||
|
||||
Before undertaking a nontrivial change to this specification, send mail to the [mailing list](#mailing-list) to discuss what you plan to do.
|
||||
This gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits.
|
||||
It also guarantees that the design is sound before code is written; a GitHub pull-request is not the place for high-level discussions.
|
||||
|
||||
Typos and grammatical errors can go straight to a pull-request.
|
||||
When in doubt, start on the [mailing-list](#mailing-list).
|
||||
|
||||
### Weekly Call
|
||||
|
||||
The contributors and maintainers of all OCI projects have a weekly meeting on Wednesdays at:
|
||||
|
||||
* 8:00 AM (USA Pacific), during [odd weeks][iso-week].
|
||||
* 2:00 PM (USA Pacific), during [even weeks][iso-week].
|
||||
|
||||
There is an [iCalendar][rfc5545] format for the meetings [here](meeting.ics).
|
||||
|
||||
Everyone is welcome to participate via [UberConference web][uberconference] or audio-only: +1 415 968 0849 (no PIN needed).
|
||||
An initial agenda will be posted to the [mailing list](#mailing-list) earlier in the week, and everyone is welcome to propose additional topics or suggest other agenda alterations there.
|
||||
Minutes are posted to the [mailing list](#mailing-list) and minutes from past calls are archived [here][minutes], with minutes from especially old meetings (September 2015 and earlier) archived [here][runtime-wiki].
|
||||
|
||||
### Mailing List
|
||||
|
||||
You can subscribe and join the mailing list on [Google Groups][dev-list].
|
||||
|
||||
### IRC
|
||||
|
||||
OCI discussion happens on #opencontainers on Freenode ([logs][irc-logs]).
|
||||
|
||||
### Git commit
|
||||
|
||||
#### Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch.
|
||||
The rules are pretty simple: if you can certify the below (from http://developercertificate.org):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe@gmail.com>
|
||||
|
||||
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
You can add the sign off when creating the git commit via `git commit -s`.
|
||||
|
||||
#### Commit Style
|
||||
|
||||
Simple house-keeping for clean git history.
|
||||
Read more on [How to Write a Git Commit Message][how-to-git-commit] or the Discussion section of [git-commit(1)][git-commit.1].
|
||||
|
||||
1. Separate the subject from body with a blank line
|
||||
2. Limit the subject line to 50 characters
|
||||
3. Capitalize the subject line
|
||||
4. Do not end the subject line with a period
|
||||
5. Use the imperative mood in the subject line
|
||||
6. Wrap the body at 72 characters
|
||||
7. Use the body to explain what and why vs. how
|
||||
* If there was important/useful/essential conversation or information, copy or include a reference
|
||||
8. When possible, one keyword to scope the change in the subject (i.e. "README: ...", "runtime: ...")
|
||||
|
||||
|
||||
[charter]: https://www.opencontainers.org/about/governance
|
||||
[code-of-conduct]: https://github.com/opencontainers/tob/blob/master/code-of-conduct.md
|
||||
[dev-list]: https://groups.google.com/a/opencontainers.org/forum/#!forum/dev
|
||||
[how-to-git-commit]: http://chris.beams.io/posts/git-commit
|
||||
[irc-logs]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/
|
||||
[iso-week]: https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date
|
||||
[minutes]: http://ircbot.wl.linuxfoundation.org/meetings/opencontainers/
|
||||
[oci]: https://www.opencontainers.org
|
||||
[rfc5545]: https://tools.ietf.org/html/rfc5545
|
||||
[runtime-wiki]: https://github.com/opencontainers/runtime-spec/wiki
|
||||
[uberconference]: https://www.uberconference.com/opencontainers
|
||||
|
||||
[git-commit.1]: http://git-scm.com/docs/git-commit
|
||||
157
vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
generated
vendored
157
vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
generated
vendored
@@ -6,26 +6,24 @@ import "os"
|
||||
type Spec struct {
|
||||
// Version of the Open Container Runtime Specification with which the bundle complies.
|
||||
Version string `json:"ociVersion"`
|
||||
// Platform specifies the configuration's target platform.
|
||||
Platform Platform `json:"platform"`
|
||||
// Process configures the container process.
|
||||
Process Process `json:"process"`
|
||||
Process *Process `json:"process,omitempty"`
|
||||
// Root configures the container's root filesystem.
|
||||
Root Root `json:"root"`
|
||||
Root *Root `json:"root,omitempty"`
|
||||
// Hostname configures the container's hostname.
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
// Mounts configures additional mounts (on top of Root).
|
||||
Mounts []Mount `json:"mounts,omitempty"`
|
||||
// Hooks configures callbacks for container lifecycle events.
|
||||
Hooks *Hooks `json:"hooks,omitempty"`
|
||||
Hooks *Hooks `json:"hooks,omitempty" platform:"linux,solaris"`
|
||||
// Annotations contains arbitrary metadata for the container.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
||||
// Linux is platform specific configuration for Linux based containers.
|
||||
// Linux is platform-specific configuration for Linux based containers.
|
||||
Linux *Linux `json:"linux,omitempty" platform:"linux"`
|
||||
// Solaris is platform specific configuration for Solaris containers.
|
||||
// Solaris is platform-specific configuration for Solaris based containers.
|
||||
Solaris *Solaris `json:"solaris,omitempty" platform:"solaris"`
|
||||
// Windows is platform specific configuration for Windows based containers, including Hyper-V containers.
|
||||
// Windows is platform-specific configuration for Windows based containers.
|
||||
Windows *Windows `json:"windows,omitempty" platform:"windows"`
|
||||
}
|
||||
|
||||
@@ -34,7 +32,7 @@ type Process struct {
|
||||
// Terminal creates an interactive terminal for the container.
|
||||
Terminal bool `json:"terminal,omitempty"`
|
||||
// ConsoleSize specifies the size of the console.
|
||||
ConsoleSize Box `json:"consoleSize,omitempty"`
|
||||
ConsoleSize *Box `json:"consoleSize,omitempty"`
|
||||
// User specifies user information for the process.
|
||||
User User `json:"user"`
|
||||
// Args specifies the binary and arguments for the application to execute.
|
||||
@@ -47,11 +45,13 @@ type Process struct {
|
||||
// Capabilities are Linux capabilities that are kept for the process.
|
||||
Capabilities *LinuxCapabilities `json:"capabilities,omitempty" platform:"linux"`
|
||||
// Rlimits specifies rlimit options to apply to the process.
|
||||
Rlimits []LinuxRlimit `json:"rlimits,omitempty" platform:"linux"`
|
||||
Rlimits []POSIXRlimit `json:"rlimits,omitempty" platform:"linux,solaris"`
|
||||
// NoNewPrivileges controls whether additional privileges could be gained by processes in the container.
|
||||
NoNewPrivileges bool `json:"noNewPrivileges,omitempty" platform:"linux"`
|
||||
// ApparmorProfile specifies the apparmor profile for the container.
|
||||
ApparmorProfile string `json:"apparmorProfile,omitempty" platform:"linux"`
|
||||
// Specify an oom_score_adj for the container.
|
||||
OOMScoreAdj *int `json:"oomScoreAdj,omitempty" platform:"linux"`
|
||||
// SelinuxLabel specifies the selinux context that the container process is run as.
|
||||
SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"`
|
||||
}
|
||||
@@ -99,23 +99,13 @@ type Root struct {
|
||||
Readonly bool `json:"readonly,omitempty"`
|
||||
}
|
||||
|
||||
// Platform specifies OS and arch information for the host system that the container
|
||||
// is created for.
|
||||
type Platform struct {
|
||||
// OS is the operating system.
|
||||
OS string `json:"os"`
|
||||
// Arch is the architecture
|
||||
Arch string `json:"arch"`
|
||||
}
|
||||
|
||||
// Mount specifies a mount for a container.
|
||||
type Mount struct {
|
||||
// Destination is the path where the mount will be placed relative to the container's root. The path and child directories MUST exist, a runtime MUST NOT create directories automatically to a mount point.
|
||||
// Destination is the absolute path where the mount will be placed in the container.
|
||||
Destination string `json:"destination"`
|
||||
// Type specifies the mount kind.
|
||||
Type string `json:"type,omitempty"`
|
||||
// Source specifies the source path of the mount. In the case of bind mounts on
|
||||
// Linux based systems this would be the file on the host.
|
||||
Type string `json:"type,omitempty" platform:"linux,solaris"`
|
||||
// Source specifies the source path of the mount.
|
||||
Source string `json:"source,omitempty"`
|
||||
// Options are fstab style mount options.
|
||||
Options []string `json:"options,omitempty"`
|
||||
@@ -132,7 +122,6 @@ type Hook struct {
|
||||
// Hooks for container setup and teardown
|
||||
type Hooks struct {
|
||||
// Prestart is a list of hooks to be run before the container process is executed.
|
||||
// On Linux, they are run after the container namespaces are created.
|
||||
Prestart []Hook `json:"prestart,omitempty"`
|
||||
// Poststart is a list of hooks to be run after the container process is started.
|
||||
Poststart []Hook `json:"poststart,omitempty"`
|
||||
@@ -140,11 +129,11 @@ type Hooks struct {
|
||||
Poststop []Hook `json:"poststop,omitempty"`
|
||||
}
|
||||
|
||||
// Linux contains platform specific configuration for Linux based containers.
|
||||
// Linux contains platform-specific configuration for Linux based containers.
|
||||
type Linux struct {
|
||||
// UIDMapping specifies user mappings for supporting user namespaces on Linux.
|
||||
// UIDMapping specifies user mappings for supporting user namespaces.
|
||||
UIDMappings []LinuxIDMapping `json:"uidMappings,omitempty"`
|
||||
// GIDMapping specifies group mappings for supporting user namespaces on Linux.
|
||||
// GIDMapping specifies group mappings for supporting user namespaces.
|
||||
GIDMappings []LinuxIDMapping `json:"gidMappings,omitempty"`
|
||||
// Sysctl are a set of key value pairs that are set for the container on start
|
||||
Sysctl map[string]string `json:"sysctl,omitempty"`
|
||||
@@ -169,11 +158,14 @@ type Linux struct {
|
||||
ReadonlyPaths []string `json:"readonlyPaths,omitempty"`
|
||||
// MountLabel specifies the selinux context for the mounts in the container.
|
||||
MountLabel string `json:"mountLabel,omitempty"`
|
||||
// IntelRdt contains Intel Resource Director Technology (RDT) information
|
||||
// for handling resource constraints (e.g., L3 cache) for the container
|
||||
IntelRdt *LinuxIntelRdt `json:"intelRdt,omitempty"`
|
||||
}
|
||||
|
||||
// LinuxNamespace is the configuration for a Linux namespace
|
||||
type LinuxNamespace struct {
|
||||
// Type is the type of Linux namespace
|
||||
// Type is the type of namespace
|
||||
Type LinuxNamespaceType `json:"type"`
|
||||
// Path is a path to an existing namespace persisted on disk that can be joined
|
||||
// and is of the same type
|
||||
@@ -210,8 +202,8 @@ type LinuxIDMapping struct {
|
||||
Size uint32 `json:"size"`
|
||||
}
|
||||
|
||||
// LinuxRlimit type and restrictions
|
||||
type LinuxRlimit struct {
|
||||
// POSIXRlimit type and restrictions
|
||||
type POSIXRlimit struct {
|
||||
// Type of the rlimit to set
|
||||
Type string `json:"type"`
|
||||
// Hard is the hard limit for the specified type
|
||||
@@ -244,12 +236,12 @@ type linuxBlockIODevice struct {
|
||||
Minor int64 `json:"minor"`
|
||||
}
|
||||
|
||||
// LinuxWeightDevice struct holds a `major:minor weight` pair for blkioWeightDevice
|
||||
// LinuxWeightDevice struct holds a `major:minor weight` pair for weightDevice
|
||||
type LinuxWeightDevice struct {
|
||||
linuxBlockIODevice
|
||||
// Weight is the bandwidth rate for the device, range is from 10 to 1000
|
||||
// Weight is the bandwidth rate for the device.
|
||||
Weight *uint16 `json:"weight,omitempty"`
|
||||
// LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
|
||||
// LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, CFQ scheduler only
|
||||
LeafWeight *uint16 `json:"leafWeight,omitempty"`
|
||||
}
|
||||
|
||||
@@ -262,36 +254,38 @@ type LinuxThrottleDevice struct {
|
||||
|
||||
// LinuxBlockIO for Linux cgroup 'blkio' resource management
|
||||
type LinuxBlockIO struct {
|
||||
// Specifies per cgroup weight, range is from 10 to 1000
|
||||
Weight *uint16 `json:"blkioWeight,omitempty"`
|
||||
// Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
|
||||
LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"`
|
||||
// Specifies per cgroup weight
|
||||
Weight *uint16 `json:"weight,omitempty"`
|
||||
// Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only
|
||||
LeafWeight *uint16 `json:"leafWeight,omitempty"`
|
||||
// Weight per cgroup per device, can override BlkioWeight
|
||||
WeightDevice []LinuxWeightDevice `json:"blkioWeightDevice,omitempty"`
|
||||
WeightDevice []LinuxWeightDevice `json:"weightDevice,omitempty"`
|
||||
// IO read rate limit per cgroup per device, bytes per second
|
||||
ThrottleReadBpsDevice []LinuxThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"`
|
||||
ThrottleReadBpsDevice []LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"`
|
||||
// IO write rate limit per cgroup per device, bytes per second
|
||||
ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"`
|
||||
ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"throttleWriteBpsDevice,omitempty"`
|
||||
// IO read rate limit per cgroup per device, IO per second
|
||||
ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"`
|
||||
ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"throttleReadIOPSDevice,omitempty"`
|
||||
// IO write rate limit per cgroup per device, IO per second
|
||||
ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"`
|
||||
ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"throttleWriteIOPSDevice,omitempty"`
|
||||
}
|
||||
|
||||
// LinuxMemory for Linux cgroup 'memory' resource management
|
||||
type LinuxMemory struct {
|
||||
// Memory limit (in bytes).
|
||||
Limit *uint64 `json:"limit,omitempty"`
|
||||
Limit *int64 `json:"limit,omitempty"`
|
||||
// Memory reservation or soft_limit (in bytes).
|
||||
Reservation *uint64 `json:"reservation,omitempty"`
|
||||
Reservation *int64 `json:"reservation,omitempty"`
|
||||
// Total memory limit (memory + swap).
|
||||
Swap *uint64 `json:"swap,omitempty"`
|
||||
Swap *int64 `json:"swap,omitempty"`
|
||||
// Kernel memory limit (in bytes).
|
||||
Kernel *uint64 `json:"kernel,omitempty"`
|
||||
Kernel *int64 `json:"kernel,omitempty"`
|
||||
// Kernel memory limit for tcp (in bytes)
|
||||
KernelTCP *uint64 `json:"kernelTCP,omitempty"`
|
||||
// How aggressive the kernel will swap memory pages. Range from 0 to 100.
|
||||
KernelTCP *int64 `json:"kernelTCP,omitempty"`
|
||||
// How aggressive the kernel will swap memory pages.
|
||||
Swappiness *uint64 `json:"swappiness,omitempty"`
|
||||
// DisableOOMKiller disables the OOM killer for out of memory conditions
|
||||
DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
|
||||
}
|
||||
|
||||
// LinuxCPU for Linux cgroup 'cpu' resource management
|
||||
@@ -330,10 +324,6 @@ type LinuxNetwork struct {
|
||||
type LinuxResources struct {
|
||||
// Devices configures the device whitelist.
|
||||
Devices []LinuxDeviceCgroup `json:"devices,omitempty"`
|
||||
// DisableOOMKiller disables the OOM killer for out of memory conditions
|
||||
DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
|
||||
// Specify an oom_score_adj for the container.
|
||||
OOMScoreAdj *int `json:"oomScoreAdj,omitempty"`
|
||||
// Memory restriction configuration
|
||||
Memory *LinuxMemory `json:"memory,omitempty"`
|
||||
// CPU resource restriction configuration
|
||||
@@ -380,7 +370,7 @@ type LinuxDeviceCgroup struct {
|
||||
Access string `json:"access,omitempty"`
|
||||
}
|
||||
|
||||
// Solaris contains platform specific configuration for Solaris application containers.
|
||||
// Solaris contains platform-specific configuration for Solaris application containers.
|
||||
type Solaris struct {
|
||||
// SMF FMRI which should go "online" before we start the container process.
|
||||
Milestone string `json:"milestone,omitempty"`
|
||||
@@ -427,8 +417,20 @@ type SolarisAnet struct {
|
||||
|
||||
// Windows defines the runtime configuration for Windows based containers, including Hyper-V containers.
|
||||
type Windows struct {
|
||||
// LayerFolders contains a list of absolute paths to directories containing image layers.
|
||||
LayerFolders []string `json:"layerFolders"`
|
||||
// Resources contains information for handling resource constraints for the container.
|
||||
Resources *WindowsResources `json:"resources,omitempty"`
|
||||
// CredentialSpec contains a JSON object describing a group Managed Service Account (gMSA) specification.
|
||||
CredentialSpec interface{} `json:"credentialSpec,omitempty"`
|
||||
// Servicing indicates if the container is being started in a mode to apply a Windows Update servicing operation.
|
||||
Servicing bool `json:"servicing,omitempty"`
|
||||
// IgnoreFlushesDuringBoot indicates if the container is being started in a mode where disk writes are not flushed during its boot process.
|
||||
IgnoreFlushesDuringBoot bool `json:"ignoreFlushesDuringBoot,omitempty"`
|
||||
// HyperV contains information for running a container with Hyper-V isolation.
|
||||
HyperV *WindowsHyperV `json:"hyperv,omitempty"`
|
||||
// Network restriction configuration.
|
||||
Network *WindowsNetwork `json:"network,omitempty"`
|
||||
}
|
||||
|
||||
// WindowsResources has container runtime resource constraints for containers running on Windows.
|
||||
@@ -439,26 +441,22 @@ type WindowsResources struct {
|
||||
CPU *WindowsCPUResources `json:"cpu,omitempty"`
|
||||
// Storage restriction configuration.
|
||||
Storage *WindowsStorageResources `json:"storage,omitempty"`
|
||||
// Network restriction configuration.
|
||||
Network *WindowsNetworkResources `json:"network,omitempty"`
|
||||
}
|
||||
|
||||
// WindowsMemoryResources contains memory resource management settings.
|
||||
type WindowsMemoryResources struct {
|
||||
// Memory limit in bytes.
|
||||
Limit *uint64 `json:"limit,omitempty"`
|
||||
// Memory reservation in bytes.
|
||||
Reservation *uint64 `json:"reservation,omitempty"`
|
||||
}
|
||||
|
||||
// WindowsCPUResources contains CPU resource management settings.
|
||||
type WindowsCPUResources struct {
|
||||
// Number of CPUs available to the container.
|
||||
Count *uint64 `json:"count,omitempty"`
|
||||
// CPU shares (relative weight to other containers with cpu shares). Range is from 1 to 10000.
|
||||
// CPU shares (relative weight to other containers with cpu shares).
|
||||
Shares *uint16 `json:"shares,omitempty"`
|
||||
// Percent of available CPUs usable by the container.
|
||||
Percent *uint8 `json:"percent,omitempty"`
|
||||
// Specifies the portion of processor cycles that this container can use as a percentage times 100.
|
||||
Maximum *uint16 `json:"maximum,omitempty"`
|
||||
}
|
||||
|
||||
// WindowsStorageResources contains storage resource management settings.
|
||||
@@ -471,17 +469,29 @@ type WindowsStorageResources struct {
|
||||
SandboxSize *uint64 `json:"sandboxSize,omitempty"`
|
||||
}
|
||||
|
||||
// WindowsNetworkResources contains network resource management settings.
|
||||
type WindowsNetworkResources struct {
|
||||
// EgressBandwidth is the maximum egress bandwidth in bytes per second.
|
||||
EgressBandwidth *uint64 `json:"egressBandwidth,omitempty"`
|
||||
// WindowsNetwork contains network settings for Windows containers.
|
||||
type WindowsNetwork struct {
|
||||
// List of HNS endpoints that the container should connect to.
|
||||
EndpointList []string `json:"endpointList,omitempty"`
|
||||
// Specifies if unqualified DNS name resolution is allowed.
|
||||
AllowUnqualifiedDNSQuery bool `json:"allowUnqualifiedDNSQuery,omitempty"`
|
||||
// Comma separated list of DNS suffixes to use for name resolution.
|
||||
DNSSearchList []string `json:"DNSSearchList,omitempty"`
|
||||
// Name (ID) of the container that we will share with the network stack.
|
||||
NetworkSharedContainerName string `json:"networkSharedContainerName,omitempty"`
|
||||
}
|
||||
|
||||
// WindowsHyperV contains information for configuring a container to run with Hyper-V isolation.
|
||||
type WindowsHyperV struct {
|
||||
// UtilityVMPath is an optional path to the image used for the Utility VM.
|
||||
UtilityVMPath string `json:"utilityVMPath,omitempty"`
|
||||
}
|
||||
|
||||
// LinuxSeccomp represents syscall restrictions
|
||||
type LinuxSeccomp struct {
|
||||
DefaultAction LinuxSeccompAction `json:"defaultAction"`
|
||||
Architectures []Arch `json:"architectures,omitempty"`
|
||||
Syscalls []LinuxSyscall `json:"syscalls"`
|
||||
Syscalls []LinuxSyscall `json:"syscalls,omitempty"`
|
||||
}
|
||||
|
||||
// Arch used for additional architectures
|
||||
@@ -540,14 +550,21 @@ const (
|
||||
type LinuxSeccompArg struct {
|
||||
Index uint `json:"index"`
|
||||
Value uint64 `json:"value"`
|
||||
ValueTwo uint64 `json:"valueTwo"`
|
||||
ValueTwo uint64 `json:"valueTwo,omitempty"`
|
||||
Op LinuxSeccompOperator `json:"op"`
|
||||
}
|
||||
|
||||
// LinuxSyscall is used to match a syscall in Seccomp
|
||||
type LinuxSyscall struct {
|
||||
Names []string `json:"names"`
|
||||
Action LinuxSeccompAction `json:"action"`
|
||||
Args []LinuxSeccompArg `json:"args"`
|
||||
Comment string `json:"comment"`
|
||||
Names []string `json:"names"`
|
||||
Action LinuxSeccompAction `json:"action"`
|
||||
Args []LinuxSeccompArg `json:"args,omitempty"`
|
||||
}
|
||||
|
||||
// LinuxIntelRdt has container runtime resource constraints
|
||||
// for Intel RDT/CAT which introduced in Linux 4.10 kernel
|
||||
type LinuxIntelRdt struct {
|
||||
// The schema for L3 cache id and capacity bitmask (CBM)
|
||||
// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
|
||||
L3CacheSchema string `json:"l3CacheSchema,omitempty"`
|
||||
}
|
||||
|
||||
2
vendor/github.com/opencontainers/runtime-spec/specs-go/state.go
generated
vendored
2
vendor/github.com/opencontainers/runtime-spec/specs-go/state.go
generated
vendored
@@ -9,7 +9,7 @@ type State struct {
|
||||
// Status is the runtime status of the container.
|
||||
Status string `json:"status"`
|
||||
// Pid is the process ID for the container process.
|
||||
Pid int `json:"pid"`
|
||||
Pid int `json:"pid,omitempty"`
|
||||
// Bundle is the path to the container's bundle directory.
|
||||
Bundle string `json:"bundle"`
|
||||
// Annotations are key values associated with the container.
|
||||
|
||||
2
vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
generated
vendored
2
vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
generated
vendored
@@ -11,7 +11,7 @@ const (
|
||||
VersionPatch = 0
|
||||
|
||||
// VersionDev indicates development branch. Releases will be empty string.
|
||||
VersionDev = "-rc5"
|
||||
VersionDev = ""
|
||||
)
|
||||
|
||||
// Version is the specification version that the package types support.
|
||||
|
||||
143
vendor/github.com/opencontainers/runtime-tools/generate/generate.go
generated
vendored
143
vendor/github.com/opencontainers/runtime-tools/generate/generate.go
generated
vendored
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
@@ -35,15 +34,11 @@ type ExportOptions struct {
|
||||
func New() Generator {
|
||||
spec := rspec.Spec{
|
||||
Version: rspec.Version,
|
||||
Platform: rspec.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
},
|
||||
Root: rspec.Root{
|
||||
Root: &rspec.Root{
|
||||
Path: "",
|
||||
Readonly: false,
|
||||
},
|
||||
Process: rspec.Process{
|
||||
Process: &rspec.Process{
|
||||
Terminal: false,
|
||||
User: rspec.User{},
|
||||
Args: []string{
|
||||
@@ -136,7 +131,7 @@ func New() Generator {
|
||||
"CAP_AUDIT_WRITE",
|
||||
},
|
||||
},
|
||||
Rlimits: []rspec.LinuxRlimit{
|
||||
Rlimits: []rspec.POSIXRlimit{
|
||||
{
|
||||
Type: "RLIMIT_NOFILE",
|
||||
Hard: uint64(1024),
|
||||
@@ -308,13 +303,13 @@ func (g *Generator) SetVersion(version string) {
|
||||
|
||||
// SetRootPath sets g.spec.Root.Path.
|
||||
func (g *Generator) SetRootPath(path string) {
|
||||
g.initSpec()
|
||||
g.initSpecRoot()
|
||||
g.spec.Root.Path = path
|
||||
}
|
||||
|
||||
// SetRootReadonly sets g.spec.Root.Readonly.
|
||||
func (g *Generator) SetRootReadonly(b bool) {
|
||||
g.initSpec()
|
||||
g.initSpecRoot()
|
||||
g.spec.Root.Readonly = b
|
||||
}
|
||||
|
||||
@@ -346,57 +341,45 @@ func (g *Generator) RemoveAnnotation(key string) {
|
||||
delete(g.spec.Annotations, key)
|
||||
}
|
||||
|
||||
// SetPlatformOS sets g.spec.Process.OS.
|
||||
func (g *Generator) SetPlatformOS(os string) {
|
||||
g.initSpec()
|
||||
g.spec.Platform.OS = os
|
||||
}
|
||||
|
||||
// SetPlatformArch sets g.spec.Platform.Arch.
|
||||
func (g *Generator) SetPlatformArch(arch string) {
|
||||
g.initSpec()
|
||||
g.spec.Platform.Arch = arch
|
||||
}
|
||||
|
||||
// SetProcessUID sets g.spec.Process.User.UID.
|
||||
func (g *Generator) SetProcessUID(uid uint32) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.User.UID = uid
|
||||
}
|
||||
|
||||
// SetProcessGID sets g.spec.Process.User.GID.
|
||||
func (g *Generator) SetProcessGID(gid uint32) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.User.GID = gid
|
||||
}
|
||||
|
||||
// SetProcessCwd sets g.spec.Process.Cwd.
|
||||
func (g *Generator) SetProcessCwd(cwd string) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.Cwd = cwd
|
||||
}
|
||||
|
||||
// SetProcessNoNewPrivileges sets g.spec.Process.NoNewPrivileges.
|
||||
func (g *Generator) SetProcessNoNewPrivileges(b bool) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.NoNewPrivileges = b
|
||||
}
|
||||
|
||||
// SetProcessTerminal sets g.spec.Process.Terminal.
|
||||
func (g *Generator) SetProcessTerminal(b bool) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.Terminal = b
|
||||
}
|
||||
|
||||
// SetProcessApparmorProfile sets g.spec.Process.ApparmorProfile.
|
||||
func (g *Generator) SetProcessApparmorProfile(prof string) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.ApparmorProfile = prof
|
||||
}
|
||||
|
||||
// SetProcessArgs sets g.spec.Process.Args.
|
||||
func (g *Generator) SetProcessArgs(args []string) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.Args = args
|
||||
}
|
||||
|
||||
@@ -411,7 +394,7 @@ func (g *Generator) ClearProcessEnv() {
|
||||
// AddProcessEnv adds name=value into g.spec.Process.Env, or replaces an
|
||||
// existing entry with the given name.
|
||||
func (g *Generator) AddProcessEnv(name, value string) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
|
||||
env := fmt.Sprintf("%s=%s", name, value)
|
||||
for idx := range g.spec.Process.Env {
|
||||
@@ -425,7 +408,7 @@ func (g *Generator) AddProcessEnv(name, value string) {
|
||||
|
||||
// AddProcessRlimits adds rlimit into g.spec.Process.Rlimits.
|
||||
func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
for i, rlimit := range g.spec.Process.Rlimits {
|
||||
if rlimit.Type == rType {
|
||||
g.spec.Process.Rlimits[i].Hard = rHard
|
||||
@@ -434,7 +417,7 @@ func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64)
|
||||
}
|
||||
}
|
||||
|
||||
newRlimit := rspec.LinuxRlimit{
|
||||
newRlimit := rspec.POSIXRlimit{
|
||||
Type: rType,
|
||||
Hard: rHard,
|
||||
Soft: rSoft,
|
||||
@@ -461,7 +444,7 @@ func (g *Generator) ClearProcessRlimits() {
|
||||
if g.spec == nil {
|
||||
return
|
||||
}
|
||||
g.spec.Process.Rlimits = []rspec.LinuxRlimit{}
|
||||
g.spec.Process.Rlimits = []rspec.POSIXRlimit{}
|
||||
}
|
||||
|
||||
// ClearProcessAdditionalGids clear g.spec.Process.AdditionalGids.
|
||||
@@ -474,7 +457,7 @@ func (g *Generator) ClearProcessAdditionalGids() {
|
||||
|
||||
// AddProcessAdditionalGid adds an additional gid into g.spec.Process.AdditionalGids.
|
||||
func (g *Generator) AddProcessAdditionalGid(gid uint32) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
for _, group := range g.spec.Process.User.AdditionalGids {
|
||||
if group == gid {
|
||||
return
|
||||
@@ -485,7 +468,7 @@ func (g *Generator) AddProcessAdditionalGid(gid uint32) {
|
||||
|
||||
// SetProcessSelinuxLabel sets g.spec.Process.SelinuxLabel.
|
||||
func (g *Generator) SetProcessSelinuxLabel(label string) {
|
||||
g.initSpec()
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.SelinuxLabel = label
|
||||
}
|
||||
|
||||
@@ -501,16 +484,10 @@ func (g *Generator) SetLinuxMountLabel(label string) {
|
||||
g.spec.Linux.MountLabel = label
|
||||
}
|
||||
|
||||
// SetLinuxResourcesDisableOOMKiller sets g.spec.Linux.Resources.DisableOOMKiller.
|
||||
func (g *Generator) SetLinuxResourcesDisableOOMKiller(disable bool) {
|
||||
g.initSpecLinuxResources()
|
||||
g.spec.Linux.Resources.DisableOOMKiller = &disable
|
||||
}
|
||||
|
||||
// SetLinuxResourcesOOMScoreAdj sets g.spec.Linux.Resources.OOMScoreAdj.
|
||||
func (g *Generator) SetLinuxResourcesOOMScoreAdj(adj int) {
|
||||
g.initSpecLinuxResources()
|
||||
g.spec.Linux.Resources.OOMScoreAdj = &adj
|
||||
// SetProcessOOMScoreAdj sets g.spec.Process.OOMScoreAdj.
|
||||
func (g *Generator) SetProcessOOMScoreAdj(adj int) {
|
||||
g.initSpecProcess()
|
||||
g.spec.Process.OOMScoreAdj = &adj
|
||||
}
|
||||
|
||||
// SetLinuxResourcesCPUShares sets g.spec.Linux.Resources.CPU.Shares.
|
||||
@@ -555,32 +532,62 @@ func (g *Generator) SetLinuxResourcesCPUMems(mems string) {
|
||||
g.spec.Linux.Resources.CPU.Mems = mems
|
||||
}
|
||||
|
||||
// AddLinuxResourcesHugepageLimit adds or sets g.spec.Linux.Resources.HugepageLimits.
|
||||
func (g *Generator) AddLinuxResourcesHugepageLimit(pageSize string, limit uint64) {
|
||||
hugepageLimit := rspec.LinuxHugepageLimit{
|
||||
Pagesize: pageSize,
|
||||
Limit: limit,
|
||||
}
|
||||
|
||||
g.initSpecLinuxResources()
|
||||
for i, pageLimit := range g.spec.Linux.Resources.HugepageLimits {
|
||||
if pageLimit.Pagesize == pageSize {
|
||||
g.spec.Linux.Resources.HugepageLimits[i].Limit = limit
|
||||
return
|
||||
}
|
||||
}
|
||||
g.spec.Linux.Resources.HugepageLimits = append(g.spec.Linux.Resources.HugepageLimits, hugepageLimit)
|
||||
}
|
||||
|
||||
// DropLinuxResourcesHugepageLimit drops a hugepage limit from g.spec.Linux.Resources.HugepageLimits.
|
||||
func (g *Generator) DropLinuxResourcesHugepageLimit(pageSize string) error {
|
||||
g.initSpecLinuxResources()
|
||||
for i, pageLimit := range g.spec.Linux.Resources.HugepageLimits {
|
||||
if pageLimit.Pagesize == pageSize {
|
||||
g.spec.Linux.Resources.HugepageLimits = append(g.spec.Linux.Resources.HugepageLimits[:i], g.spec.Linux.Resources.HugepageLimits[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLinuxResourcesMemoryLimit sets g.spec.Linux.Resources.Memory.Limit.
|
||||
func (g *Generator) SetLinuxResourcesMemoryLimit(limit uint64) {
|
||||
func (g *Generator) SetLinuxResourcesMemoryLimit(limit int64) {
|
||||
g.initSpecLinuxResourcesMemory()
|
||||
g.spec.Linux.Resources.Memory.Limit = &limit
|
||||
}
|
||||
|
||||
// SetLinuxResourcesMemoryReservation sets g.spec.Linux.Resources.Memory.Reservation.
|
||||
func (g *Generator) SetLinuxResourcesMemoryReservation(reservation uint64) {
|
||||
func (g *Generator) SetLinuxResourcesMemoryReservation(reservation int64) {
|
||||
g.initSpecLinuxResourcesMemory()
|
||||
g.spec.Linux.Resources.Memory.Reservation = &reservation
|
||||
}
|
||||
|
||||
// SetLinuxResourcesMemorySwap sets g.spec.Linux.Resources.Memory.Swap.
|
||||
func (g *Generator) SetLinuxResourcesMemorySwap(swap uint64) {
|
||||
func (g *Generator) SetLinuxResourcesMemorySwap(swap int64) {
|
||||
g.initSpecLinuxResourcesMemory()
|
||||
g.spec.Linux.Resources.Memory.Swap = &swap
|
||||
}
|
||||
|
||||
// SetLinuxResourcesMemoryKernel sets g.spec.Linux.Resources.Memory.Kernel.
|
||||
func (g *Generator) SetLinuxResourcesMemoryKernel(kernel uint64) {
|
||||
func (g *Generator) SetLinuxResourcesMemoryKernel(kernel int64) {
|
||||
g.initSpecLinuxResourcesMemory()
|
||||
g.spec.Linux.Resources.Memory.Kernel = &kernel
|
||||
}
|
||||
|
||||
// SetLinuxResourcesMemoryKernelTCP sets g.spec.Linux.Resources.Memory.KernelTCP.
|
||||
func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP uint64) {
|
||||
func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP int64) {
|
||||
g.initSpecLinuxResourcesMemory()
|
||||
g.spec.Linux.Resources.Memory.KernelTCP = &kernelTCP
|
||||
}
|
||||
@@ -591,6 +598,12 @@ func (g *Generator) SetLinuxResourcesMemorySwappiness(swappiness uint64) {
|
||||
g.spec.Linux.Resources.Memory.Swappiness = &swappiness
|
||||
}
|
||||
|
||||
// SetLinuxResourcesMemoryDisableOOMKiller sets g.spec.Linux.Resources.Memory.DisableOOMKiller.
|
||||
func (g *Generator) SetLinuxResourcesMemoryDisableOOMKiller(disable bool) {
|
||||
g.initSpecLinuxResourcesMemory()
|
||||
g.spec.Linux.Resources.Memory.DisableOOMKiller = &disable
|
||||
}
|
||||
|
||||
// SetLinuxResourcesNetworkClassID sets g.spec.Linux.Resources.Network.ClassID.
|
||||
func (g *Generator) SetLinuxResourcesNetworkClassID(classid uint32) {
|
||||
g.initSpecLinuxResourcesNetwork()
|
||||
@@ -714,12 +727,15 @@ func (g *Generator) ClearPreStartHooks() {
|
||||
if g.spec == nil {
|
||||
return
|
||||
}
|
||||
if g.spec.Hooks == nil {
|
||||
return
|
||||
}
|
||||
g.spec.Hooks.Prestart = []rspec.Hook{}
|
||||
}
|
||||
|
||||
// AddPreStartHook add a prestart hook into g.spec.Hooks.Prestart.
|
||||
func (g *Generator) AddPreStartHook(path string, args []string) {
|
||||
g.initSpec()
|
||||
g.initSpecHooks()
|
||||
hook := rspec.Hook{Path: path, Args: args}
|
||||
g.spec.Hooks.Prestart = append(g.spec.Hooks.Prestart, hook)
|
||||
}
|
||||
@@ -729,12 +745,15 @@ func (g *Generator) ClearPostStopHooks() {
|
||||
if g.spec == nil {
|
||||
return
|
||||
}
|
||||
if g.spec.Hooks == nil {
|
||||
return
|
||||
}
|
||||
g.spec.Hooks.Poststop = []rspec.Hook{}
|
||||
}
|
||||
|
||||
// AddPostStopHook adds a poststop hook into g.spec.Hooks.Poststop.
|
||||
func (g *Generator) AddPostStopHook(path string, args []string) {
|
||||
g.initSpec()
|
||||
g.initSpecHooks()
|
||||
hook := rspec.Hook{Path: path, Args: args}
|
||||
g.spec.Hooks.Poststop = append(g.spec.Hooks.Poststop, hook)
|
||||
}
|
||||
@@ -744,12 +763,15 @@ func (g *Generator) ClearPostStartHooks() {
|
||||
if g.spec == nil {
|
||||
return
|
||||
}
|
||||
if g.spec.Hooks == nil {
|
||||
return
|
||||
}
|
||||
g.spec.Hooks.Poststart = []rspec.Hook{}
|
||||
}
|
||||
|
||||
// AddPostStartHook adds a poststart hook into g.spec.Hooks.Poststart.
|
||||
func (g *Generator) AddPostStartHook(path string, args []string) {
|
||||
g.initSpec()
|
||||
g.initSpecHooks()
|
||||
hook := rspec.Hook{Path: path, Args: args}
|
||||
g.spec.Hooks.Poststart = append(g.spec.Hooks.Poststart, hook)
|
||||
}
|
||||
@@ -830,6 +852,7 @@ func (g *Generator) SetupPrivileged(privileged bool) {
|
||||
finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())))
|
||||
}
|
||||
g.initSpecLinux()
|
||||
g.initSpecProcessCapabilities()
|
||||
g.spec.Process.Capabilities.Bounding = finalCapList
|
||||
g.spec.Process.Capabilities.Effective = finalCapList
|
||||
g.spec.Process.Capabilities.Inheritable = finalCapList
|
||||
@@ -860,7 +883,7 @@ func (g *Generator) AddProcessCapability(c string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
g.initSpec()
|
||||
g.initSpecProcessCapabilities()
|
||||
|
||||
for _, cap := range g.spec.Process.Capabilities.Bounding {
|
||||
if strings.ToUpper(cap) == cp {
|
||||
@@ -907,40 +930,35 @@ func (g *Generator) DropProcessCapability(c string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
g.initSpec()
|
||||
g.initSpecProcessCapabilities()
|
||||
|
||||
for i, cap := range g.spec.Process.Capabilities.Bounding {
|
||||
if strings.ToUpper(cap) == cp {
|
||||
g.spec.Process.Capabilities.Bounding = append(g.spec.Process.Capabilities.Bounding[:i], g.spec.Process.Capabilities.Bounding[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for i, cap := range g.spec.Process.Capabilities.Effective {
|
||||
if strings.ToUpper(cap) == cp {
|
||||
g.spec.Process.Capabilities.Effective = append(g.spec.Process.Capabilities.Effective[:i], g.spec.Process.Capabilities.Effective[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for i, cap := range g.spec.Process.Capabilities.Inheritable {
|
||||
if strings.ToUpper(cap) == cp {
|
||||
g.spec.Process.Capabilities.Inheritable = append(g.spec.Process.Capabilities.Inheritable[:i], g.spec.Process.Capabilities.Inheritable[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for i, cap := range g.spec.Process.Capabilities.Permitted {
|
||||
if strings.ToUpper(cap) == cp {
|
||||
g.spec.Process.Capabilities.Permitted = append(g.spec.Process.Capabilities.Permitted[:i], g.spec.Process.Capabilities.Permitted[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for i, cap := range g.spec.Process.Capabilities.Ambient {
|
||||
if strings.ToUpper(cap) == cp {
|
||||
g.spec.Process.Capabilities.Ambient = append(g.spec.Process.Capabilities.Ambient[:i], g.spec.Process.Capabilities.Ambient[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -964,7 +982,7 @@ func mapStrToNamespace(ns string, path string) (rspec.LinuxNamespace, error) {
|
||||
case "cgroup":
|
||||
return rspec.LinuxNamespace{Type: rspec.CgroupNamespace, Path: path}, nil
|
||||
default:
|
||||
return rspec.LinuxNamespace{}, fmt.Errorf("Should not reach here!")
|
||||
return rspec.LinuxNamespace{}, fmt.Errorf("unrecognized namespace %q", ns)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1049,7 @@ func (g *Generator) AddDevice(device rspec.LinuxDevice) {
|
||||
g.spec.Linux.Devices = append(g.spec.Linux.Devices, device)
|
||||
}
|
||||
|
||||
//RemoveDevice remove a device from g.spec.Linux.Devices
|
||||
// RemoveDevice remove a device from g.spec.Linux.Devices
|
||||
func (g *Generator) RemoveDevice(path string) error {
|
||||
if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Devices == nil {
|
||||
return nil
|
||||
@@ -1046,6 +1064,7 @@ func (g *Generator) RemoveDevice(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearLinuxDevices clears g.spec.Linux.Devices
|
||||
func (g *Generator) ClearLinuxDevices() {
|
||||
if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Devices == nil {
|
||||
return
|
||||
|
||||
14
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go
generated
vendored
14
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go
generated
vendored
@@ -30,8 +30,9 @@ func ParseSyscallFlag(args SyscallOpts, config *rspec.LinuxSeccomp) error {
|
||||
}
|
||||
|
||||
action, _ := parseAction(arguments[0])
|
||||
if action == config.DefaultAction {
|
||||
return fmt.Errorf("default action already set as %s", action)
|
||||
if action == config.DefaultAction && args.argsAreEmpty() {
|
||||
// default already set, no need to make changes
|
||||
return nil
|
||||
}
|
||||
|
||||
var newSyscall rspec.LinuxSyscall
|
||||
@@ -96,7 +97,7 @@ func ParseDefaultAction(action string, config *rspec.LinuxSeccomp) error {
|
||||
return err
|
||||
}
|
||||
config.DefaultAction = defaultAction
|
||||
err = RemoveAllMatchingRules(config, action)
|
||||
err = RemoveAllMatchingRules(config, defaultAction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -125,3 +126,10 @@ func newSyscallStruct(name string, action rspec.LinuxSeccompAction, args []rspec
|
||||
}
|
||||
return syscallStruct
|
||||
}
|
||||
|
||||
func (s SyscallOpts) argsAreEmpty() bool {
|
||||
return (s.Index == "" &&
|
||||
s.Value == "" &&
|
||||
s.ValueTwo == "" &&
|
||||
s.Operator == "")
|
||||
}
|
||||
|
||||
14
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go
generated
vendored
14
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go
generated
vendored
@@ -15,12 +15,7 @@ func RemoveAction(arguments string, config *rspec.LinuxSeccomp) error {
|
||||
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
|
||||
}
|
||||
|
||||
var syscallsToRemove []string
|
||||
if strings.Contains(arguments, ",") {
|
||||
syscallsToRemove = strings.Split(arguments, ",")
|
||||
} else {
|
||||
syscallsToRemove = append(syscallsToRemove, arguments)
|
||||
}
|
||||
syscallsToRemove := strings.Split(arguments, ",")
|
||||
|
||||
for counter, syscallStruct := range config.Syscalls {
|
||||
if reflect.DeepEqual(syscallsToRemove, syscallStruct.Names) {
|
||||
@@ -42,16 +37,11 @@ func RemoveAllSeccompRules(config *rspec.LinuxSeccomp) error {
|
||||
}
|
||||
|
||||
// RemoveAllMatchingRules will remove any syscall rules that match the specified action
|
||||
func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, action string) error {
|
||||
func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, seccompAction rspec.LinuxSeccompAction) error {
|
||||
if config == nil {
|
||||
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
|
||||
}
|
||||
|
||||
seccompAction, err := parseAction(action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, syscall := range config.Syscalls {
|
||||
if reflect.DeepEqual(syscall.Action, seccompAction) {
|
||||
RemoveAction(strings.Join(syscall.Names, ","), config)
|
||||
|
||||
25
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
generated
vendored
25
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
generated
vendored
@@ -370,26 +370,25 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp {
|
||||
var sysCloneFlagsIndex uint
|
||||
|
||||
capSysAdmin := false
|
||||
var cap string
|
||||
var caps []string
|
||||
caps := make(map[string]bool)
|
||||
|
||||
for _, cap = range rs.Process.Capabilities.Bounding {
|
||||
caps = append(caps, cap)
|
||||
for _, cap := range rs.Process.Capabilities.Bounding {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap = range rs.Process.Capabilities.Effective {
|
||||
caps = append(caps, cap)
|
||||
for _, cap := range rs.Process.Capabilities.Effective {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap = range rs.Process.Capabilities.Inheritable {
|
||||
caps = append(caps, cap)
|
||||
for _, cap := range rs.Process.Capabilities.Inheritable {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap = range rs.Process.Capabilities.Permitted {
|
||||
caps = append(caps, cap)
|
||||
for _, cap := range rs.Process.Capabilities.Permitted {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap = range rs.Process.Capabilities.Ambient {
|
||||
caps = append(caps, cap)
|
||||
for _, cap := range rs.Process.Capabilities.Ambient {
|
||||
caps[cap] = true
|
||||
}
|
||||
|
||||
for _, cap = range caps {
|
||||
for cap := range caps {
|
||||
switch cap {
|
||||
case "CAP_DAC_READ_SEARCH":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
|
||||
28
vendor/github.com/opencontainers/runtime-tools/generate/spec.go
generated
vendored
28
vendor/github.com/opencontainers/runtime-tools/generate/spec.go
generated
vendored
@@ -10,6 +10,27 @@ func (g *Generator) initSpec() {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initSpecProcess() {
|
||||
g.initSpec()
|
||||
if g.spec.Process == nil {
|
||||
g.spec.Process = &rspec.Process{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initSpecProcessCapabilities() {
|
||||
g.initSpecProcess()
|
||||
if g.spec.Process.Capabilities == nil {
|
||||
g.spec.Process.Capabilities = &rspec.LinuxCapabilities{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initSpecRoot() {
|
||||
g.initSpec()
|
||||
if g.spec.Root == nil {
|
||||
g.spec.Root = &rspec.Root{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initSpecAnnotations() {
|
||||
g.initSpec()
|
||||
if g.spec.Annotations == nil {
|
||||
@@ -17,6 +38,13 @@ func (g *Generator) initSpecAnnotations() {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initSpecHooks() {
|
||||
g.initSpec()
|
||||
if g.spec.Hooks == nil {
|
||||
g.spec.Hooks = &rspec.Hooks{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initSpecLinux() {
|
||||
g.initSpec()
|
||||
if g.spec.Linux == nil {
|
||||
|
||||
193
vendor/github.com/opencontainers/runtime-tools/validate/validate.go
generated
vendored
193
vendor/github.com/opencontainers/runtime-tools/validate/validate.go
generated
vendored
@@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@@ -47,15 +48,27 @@ type Validator struct {
|
||||
spec *rspec.Spec
|
||||
bundlePath string
|
||||
HostSpecific bool
|
||||
platform string
|
||||
}
|
||||
|
||||
// NewValidator creates a Validator
|
||||
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool) Validator {
|
||||
return Validator{spec: spec, bundlePath: bundlePath, HostSpecific: hostSpecific}
|
||||
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool, platform string) Validator {
|
||||
if hostSpecific && platform != runtime.GOOS {
|
||||
platform = runtime.GOOS
|
||||
}
|
||||
return Validator{
|
||||
spec: spec,
|
||||
bundlePath: bundlePath,
|
||||
HostSpecific: hostSpecific,
|
||||
platform: platform,
|
||||
}
|
||||
}
|
||||
|
||||
// NewValidatorFromPath creates a Validator with specified bundle path
|
||||
func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, error) {
|
||||
func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) (Validator, error) {
|
||||
if hostSpecific && platform != runtime.GOOS {
|
||||
platform = runtime.GOOS
|
||||
}
|
||||
if bundlePath == "" {
|
||||
return Validator{}, fmt.Errorf("Bundle path shouldn't be empty")
|
||||
}
|
||||
@@ -77,20 +90,21 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, erro
|
||||
return Validator{}, err
|
||||
}
|
||||
|
||||
return NewValidator(&spec, bundlePath, hostSpecific), nil
|
||||
return NewValidator(&spec, bundlePath, hostSpecific, platform), nil
|
||||
}
|
||||
|
||||
// CheckAll checks all parts of runtime bundle
|
||||
func (v *Validator) CheckAll() (msgs []string) {
|
||||
msgs = append(msgs, v.CheckPlatform()...)
|
||||
msgs = append(msgs, v.CheckRootfsPath()...)
|
||||
msgs = append(msgs, v.CheckMandatoryFields()...)
|
||||
msgs = append(msgs, v.CheckSemVer()...)
|
||||
msgs = append(msgs, v.CheckMounts()...)
|
||||
msgs = append(msgs, v.CheckPlatform()...)
|
||||
msgs = append(msgs, v.CheckProcess()...)
|
||||
msgs = append(msgs, v.CheckOS()...)
|
||||
msgs = append(msgs, v.CheckLinux()...)
|
||||
msgs = append(msgs, v.CheckHooks()...)
|
||||
if v.spec.Linux != nil {
|
||||
msgs = append(msgs, v.CheckLinux()...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -129,8 +143,13 @@ func (v *Validator) CheckRootfsPath() (msgs []string) {
|
||||
msgs = append(msgs, fmt.Sprintf("root.path is %q, but it MUST be a child of %q", v.spec.Root.Path, absBundlePath))
|
||||
}
|
||||
|
||||
return
|
||||
if v.platform == "windows" {
|
||||
if v.spec.Root.Readonly {
|
||||
msgs = append(msgs, "root.readonly field MUST be omitted or false when target platform is windows")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckSemVer checks v.spec.Version
|
||||
@@ -149,37 +168,6 @@ func (v *Validator) CheckSemVer() (msgs []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// CheckPlatform checks v.spec.Platform
|
||||
func (v *Validator) CheckPlatform() (msgs []string) {
|
||||
logrus.Debugf("check platform")
|
||||
|
||||
validCombins := map[string][]string{
|
||||
"android": {"arm"},
|
||||
"darwin": {"386", "amd64", "arm", "arm64"},
|
||||
"dragonfly": {"amd64"},
|
||||
"freebsd": {"386", "amd64", "arm"},
|
||||
"linux": {"386", "amd64", "arm", "arm64", "ppc64", "ppc64le", "mips64", "mips64le", "s390x"},
|
||||
"netbsd": {"386", "amd64", "arm"},
|
||||
"openbsd": {"386", "amd64", "arm"},
|
||||
"plan9": {"386", "amd64"},
|
||||
"solaris": {"amd64"},
|
||||
"windows": {"386", "amd64"}}
|
||||
platform := v.spec.Platform
|
||||
for os, archs := range validCombins {
|
||||
if os == platform.OS {
|
||||
for _, arch := range archs {
|
||||
if arch == platform.Arch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, fmt.Sprintf("Combination of %q and %q is invalid.", platform.OS, platform.Arch))
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, fmt.Sprintf("Operation system %q of the bundle is not supported yet.", platform.OS))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckHooks check v.spec.Hooks
|
||||
func (v *Validator) CheckHooks() (msgs []string) {
|
||||
logrus.Debugf("check hooks")
|
||||
@@ -259,11 +247,12 @@ func (v *Validator) CheckProcess() (msgs []string) {
|
||||
}
|
||||
}
|
||||
|
||||
msgs = append(msgs, v.CheckCapablities()...)
|
||||
if v.spec.Process.Capabilities != nil {
|
||||
msgs = append(msgs, v.CheckCapabilities()...)
|
||||
}
|
||||
msgs = append(msgs, v.CheckRlimits()...)
|
||||
|
||||
if v.spec.Platform.OS == "linux" {
|
||||
|
||||
if v.platform == "linux" {
|
||||
if len(process.ApparmorProfile) > 0 {
|
||||
profilePath := filepath.Join(v.bundlePath, v.spec.Root.Path, "/etc/apparmor.d", process.ApparmorProfile)
|
||||
_, err := os.Stat(profilePath)
|
||||
@@ -276,39 +265,64 @@ func (v *Validator) CheckProcess() (msgs []string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (v *Validator) CheckCapablities() (msgs []string) {
|
||||
// CheckCapabilities checks v.spec.Process.Capabilities
|
||||
func (v *Validator) CheckCapabilities() (msgs []string) {
|
||||
process := v.spec.Process
|
||||
if v.spec.Platform.OS == "linux" {
|
||||
var caps []string
|
||||
if v.platform == "linux" {
|
||||
var effective, permitted, inheritable, ambient bool
|
||||
caps := make(map[string][]string)
|
||||
|
||||
for _, cap := range process.Capabilities.Bounding {
|
||||
caps = append(caps, cap)
|
||||
caps[cap] = append(caps[cap], "bounding")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Effective {
|
||||
caps = append(caps, cap)
|
||||
caps[cap] = append(caps[cap], "effective")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Inheritable {
|
||||
caps = append(caps, cap)
|
||||
caps[cap] = append(caps[cap], "inheritable")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Permitted {
|
||||
caps = append(caps, cap)
|
||||
caps[cap] = append(caps[cap], "permitted")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Ambient {
|
||||
caps = append(caps, cap)
|
||||
caps[cap] = append(caps[cap], "ambient")
|
||||
}
|
||||
|
||||
for _, capability := range caps {
|
||||
for capability, owns := range caps {
|
||||
if err := CapValid(capability, v.HostSpecific); err != nil {
|
||||
msgs = append(msgs, fmt.Sprintf("capability %q is not valid, man capabilities(7)", capability))
|
||||
}
|
||||
|
||||
effective, permitted, ambient, inheritable = false, false, false, false
|
||||
for _, set := range owns {
|
||||
if set == "effective" {
|
||||
effective = true
|
||||
}
|
||||
if set == "inheritable" {
|
||||
inheritable = true
|
||||
}
|
||||
if set == "permitted" {
|
||||
permitted = true
|
||||
}
|
||||
if set == "ambient" {
|
||||
ambient = true
|
||||
}
|
||||
}
|
||||
if effective && !permitted {
|
||||
msgs = append(msgs, fmt.Sprintf("effective capability %q is not allowed, as it's not permitted", capability))
|
||||
}
|
||||
if ambient && !(effective && inheritable) {
|
||||
msgs = append(msgs, fmt.Sprintf("ambient capability %q is not allowed, as it's not permitted and inheribate", capability))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.spec.Platform.OS)
|
||||
logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.platform)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckRlimits checks v.spec.Process.Rlimits
|
||||
func (v *Validator) CheckRlimits() (msgs []string) {
|
||||
process := v.spec.Process
|
||||
for index, rlimit := range process.Rlimits {
|
||||
@@ -317,14 +331,7 @@ func (v *Validator) CheckRlimits() (msgs []string) {
|
||||
msgs = append(msgs, fmt.Sprintf("rlimit can not contain the same type %q.", process.Rlimits[index].Type))
|
||||
}
|
||||
}
|
||||
|
||||
if v.spec.Platform.OS == "linux" {
|
||||
if err := rlimitValid(rlimit); err != nil {
|
||||
msgs = append(msgs, err.Error())
|
||||
}
|
||||
} else {
|
||||
logrus.Warnf("process.rlimits validation not yet implemented for OS %q", v.spec.Platform.OS)
|
||||
}
|
||||
msgs = append(msgs, v.rlimitValid(rlimit)...)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -375,46 +382,39 @@ func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error)
|
||||
func (v *Validator) CheckMounts() (msgs []string) {
|
||||
logrus.Debugf("check mounts")
|
||||
|
||||
supportedTypes, err := supportedMountTypes(v.spec.Platform.OS, v.HostSpecific)
|
||||
supportedTypes, err := supportedMountTypes(v.platform, v.HostSpecific)
|
||||
if err != nil {
|
||||
msgs = append(msgs, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if supportedTypes != nil {
|
||||
for _, mount := range v.spec.Mounts {
|
||||
for _, mount := range v.spec.Mounts {
|
||||
if supportedTypes != nil {
|
||||
if !supportedTypes[mount.Type] {
|
||||
msgs = append(msgs, fmt.Sprintf("Unsupported mount type %q", mount.Type))
|
||||
}
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(mount.Destination) {
|
||||
msgs = append(msgs, fmt.Sprintf("destination %v is not an absolute path", mount.Destination))
|
||||
}
|
||||
if !filepath.IsAbs(mount.Destination) {
|
||||
msgs = append(msgs, fmt.Sprintf("destination %v is not an absolute path", mount.Destination))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckOS checks v.spec.Platform.OS
|
||||
func (v *Validator) CheckOS() (msgs []string) {
|
||||
logrus.Debugf("check os")
|
||||
// CheckPlatform checks v.platform
|
||||
func (v *Validator) CheckPlatform() (msgs []string) {
|
||||
logrus.Debugf("check platform")
|
||||
|
||||
if v.spec.Platform.OS != "linux" {
|
||||
if v.spec.Linux != nil {
|
||||
msgs = append(msgs, fmt.Sprintf("'linux' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
|
||||
}
|
||||
if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" {
|
||||
msgs = append(msgs, fmt.Sprintf("platform %q is not supported", v.platform))
|
||||
return
|
||||
}
|
||||
|
||||
if v.spec.Platform.OS != "solaris" {
|
||||
if v.spec.Solaris != nil {
|
||||
msgs = append(msgs, fmt.Sprintf("'solaris' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
|
||||
}
|
||||
}
|
||||
|
||||
if v.spec.Platform.OS != "windows" {
|
||||
if v.spec.Windows != nil {
|
||||
msgs = append(msgs, fmt.Sprintf("'windows' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
|
||||
if v.platform == "windows" {
|
||||
if v.spec.Windows == nil {
|
||||
msgs = append(msgs, "'windows' MUST be set when platform is `windows`")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,7 +475,7 @@ func (v *Validator) CheckLinux() (msgs []string) {
|
||||
}
|
||||
}
|
||||
|
||||
if v.spec.Platform.OS == "linux" && !typeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
|
||||
if v.platform == "linux" && !typeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
|
||||
msgs = append(msgs, fmt.Sprintf("On Linux, hostname requires a new UTS namespace to be specified as well"))
|
||||
}
|
||||
|
||||
@@ -503,19 +503,21 @@ func (v *Validator) CheckLinux() (msgs []string) {
|
||||
case "rslave":
|
||||
case "shared":
|
||||
case "rshared":
|
||||
case "unbindable":
|
||||
case "runbindable":
|
||||
default:
|
||||
msgs = append(msgs, "rootfsPropagation must be empty or one of \"private|rprivate|slave|rslave|shared|rshared\"")
|
||||
msgs = append(msgs, "rootfsPropagation must be empty or one of \"private|rprivate|slave|rslave|shared|rshared|unbindable|runbindable\"")
|
||||
}
|
||||
|
||||
for _, maskedPath := range v.spec.Linux.MaskedPaths {
|
||||
if !strings.HasPrefix(maskedPath, "/") {
|
||||
msgs = append(msgs, "maskedPath %v is not an absolute path", maskedPath)
|
||||
msgs = append(msgs, fmt.Sprintf("maskedPath %v is not an absolute path", maskedPath))
|
||||
}
|
||||
}
|
||||
|
||||
for _, readonlyPath := range v.spec.Linux.ReadonlyPaths {
|
||||
if !strings.HasPrefix(readonlyPath, "/") {
|
||||
msgs = append(msgs, "readonlyPath %v is not an absolute path", readonlyPath)
|
||||
msgs = append(msgs, fmt.Sprintf("readonlyPath %v is not an absolute path", readonlyPath))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,16 +652,23 @@ func envValid(env string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func rlimitValid(rlimit rspec.LinuxRlimit) error {
|
||||
func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (msgs []string) {
|
||||
if rlimit.Hard < rlimit.Soft {
|
||||
return fmt.Errorf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type)
|
||||
msgs = append(msgs, fmt.Sprintf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type))
|
||||
}
|
||||
for _, val := range defaultRlimits {
|
||||
if val == rlimit.Type {
|
||||
return nil
|
||||
|
||||
if v.platform == "linux" {
|
||||
for _, val := range defaultRlimits {
|
||||
if val == rlimit.Type {
|
||||
return
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, fmt.Sprintf("rlimit type %q is invalid", rlimit.Type))
|
||||
} else {
|
||||
logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform)
|
||||
}
|
||||
return fmt.Errorf("rlimit type %q is invalid", rlimit.Type)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func namespaceValid(ns rspec.LinuxNamespace) bool {
|
||||
|
||||
Reference in New Issue
Block a user