Merge pull request #9095 from thaJeztah/isolate_platform

This commit is contained in:
Phil Estes 2023-09-14 08:31:50 -04:00 committed by GitHub
commit 3f315fcabf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 95 additions and 55 deletions

View File

@ -0,0 +1,47 @@
/*
Copyright The containerd Authors.
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 types
import oci "github.com/opencontainers/image-spec/specs-go/v1"
// OCIPlatformToProto converts from a slice of OCI [specs.Platform] to a
// slice of the protobuf definition [Platform].
func OCIPlatformToProto(platforms []oci.Platform) []*Platform {
ap := make([]*Platform, len(platforms))
for i := range platforms {
ap[i] = &Platform{
OS: platforms[i].OS,
Architecture: platforms[i].Architecture,
Variant: platforms[i].Variant,
}
}
return ap
}
// OCIPlatformFromProto converts a slice of the protobuf definition [Platform]
// to a slice of OCI [specs.Platform].
func OCIPlatformFromProto(platforms []*Platform) []oci.Platform {
op := make([]oci.Platform, len(platforms))
for i := range platforms {
op[i] = oci.Platform{
OS: platforms[i].OS,
Architecture: platforms[i].Architecture,
Variant: platforms[i].Variant,
}
}
return op
}

View File

@ -156,7 +156,7 @@ func (iis *ImageExportStream) UnmarshalAny(ctx context.Context, sm streaming.Str
return err return err
} }
specified := platforms.FromProto(s.Platforms) specified := types.OCIPlatformFromProto(s.Platforms)
iis.stream = tstreaming.WriteByteStream(ctx, stream) iis.stream = tstreaming.WriteByteStream(ctx, stream)
iis.mediaType = s.MediaType iis.mediaType = s.MediaType
iis.platforms = specified iis.platforms = specified

View File

@ -363,7 +363,7 @@ func (is *Store) MarshalAny(context.Context, streaming.StreamCreator) (typeurl.A
Labels: is.imageLabels, Labels: is.imageLabels,
ManifestLimit: uint32(is.manifestLimit), ManifestLimit: uint32(is.manifestLimit),
AllMetadata: is.allMetadata, AllMetadata: is.allMetadata,
Platforms: platforms.ToProto(is.platforms), Platforms: types.OCIPlatformToProto(is.platforms),
ExtraReferences: referencesToProto(is.extraReferences), ExtraReferences: referencesToProto(is.extraReferences),
Unpacks: unpackToProto(is.unpacks), Unpacks: unpackToProto(is.unpacks),
} }
@ -380,7 +380,7 @@ func (is *Store) UnmarshalAny(ctx context.Context, sm streaming.StreamGetter, a
is.imageLabels = s.Labels is.imageLabels = s.Labels
is.manifestLimit = int(s.ManifestLimit) is.manifestLimit = int(s.ManifestLimit)
is.allMetadata = s.AllMetadata is.allMetadata = s.AllMetadata
is.platforms = platforms.FromProto(s.Platforms) is.platforms = types.OCIPlatformFromProto(s.Platforms)
is.extraReferences = referencesFromProto(s.ExtraReferences) is.extraReferences = referencesFromProto(s.ExtraReferences)
is.unpacks = unpackFromProto(s.Unpacks) is.unpacks = unpackFromProto(s.Unpacks)

View File

@ -19,12 +19,12 @@ package platforms
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"errors"
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
"strings" "strings"
"github.com/containerd/containerd/errdefs"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -70,7 +70,7 @@ func getCPUInfo(pattern string) (info string, err error) {
return "", err return "", err
} }
return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errdefs.ErrNotFound) return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errNotFound)
} }
// getCPUVariantFromArch get CPU variant from arch through a system call // getCPUVariantFromArch get CPU variant from arch through a system call
@ -101,7 +101,7 @@ func getCPUVariantFromArch(arch string) (string, error) {
variant = "unknown" variant = "unknown"
} }
} else { } else {
return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errdefs.ErrInvalidArgument) return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errInvalidArgument)
} }
return variant, nil return variant, nil
} }
@ -112,10 +112,9 @@ func getCPUVariantFromArch(arch string) (string, error) {
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo // This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
// was not present. // was not present.
func getCPUVariant() (string, error) { func getCPUVariant() (string, error) {
variant, err := getCPUInfo("Cpu architecture") variant, err := getCPUInfo("Cpu architecture")
if err != nil { if err != nil {
if errdefs.IsNotFound(err) { if errors.Is(err, errNotFound) {
// Let's try getting CPU variant from machine architecture // Let's try getting CPU variant from machine architecture
arch, err := getMachineArch() arch, err := getMachineArch()
if err != nil { if err != nil {

View File

@ -20,8 +20,6 @@ import (
"errors" "errors"
"runtime" "runtime"
"testing" "testing"
"github.com/containerd/containerd/errdefs"
) )
func TestCPUVariant(t *testing.T) { func TestCPUVariant(t *testing.T) {
@ -107,13 +105,13 @@ func TestGetCPUVariantFromArch(t *testing.T) {
name: "Test invalid input which doesn't start with armv", name: "Test invalid input which doesn't start with armv",
input: "armxxxx", input: "armxxxx",
output: "", output: "",
expectedErr: errdefs.ErrInvalidArgument, expectedErr: errInvalidArgument,
}, },
{ {
name: "Test invalid input whose length is less than 5", name: "Test invalid input whose length is less than 5",
input: "armv", input: "armv",
output: "", output: "",
expectedErr: errdefs.ErrInvalidArgument, expectedErr: errInvalidArgument,
}, },
} { } {
t.Run(testcase.name, func(t *testing.T) { t.Run(testcase.name, func(t *testing.T) {

View File

@ -21,8 +21,6 @@ package platforms
import ( import (
"fmt" "fmt"
"runtime" "runtime"
"github.com/containerd/containerd/errdefs"
) )
func getCPUVariant() (string, error) { func getCPUVariant() (string, error) {
@ -49,10 +47,8 @@ func getCPUVariant() (string, error) {
default: default:
variant = "unknown" variant = "unknown"
} }
} else { } else {
return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errdefs.ErrNotImplemented) return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
} }
return variant, nil return variant, nil

30
platforms/errors.go Normal file
View File

@ -0,0 +1,30 @@
/*
Copyright The containerd Authors.
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 platforms
import "errors"
// These errors mirror the errors defined in [github.com/containerd/containerd/errdefs],
// however, they are not exported as they are not expected to be used as sentinel
// errors by consumers of this package.
//
//nolint:unused // not all errors are used on all platforms.
var (
errNotFound = errors.New("not found")
errInvalidArgument = errors.New("invalid argument")
errNotImplemented = errors.New("not implemented")
)

View File

@ -118,9 +118,6 @@ import (
"strings" "strings"
specs "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/errdefs"
) )
var ( var (
@ -186,14 +183,14 @@ func ParseAll(specifiers []string) ([]specs.Platform, error) {
func Parse(specifier string) (specs.Platform, error) { func Parse(specifier string) (specs.Platform, error) {
if strings.Contains(specifier, "*") { if strings.Contains(specifier, "*") {
// TODO(stevvooe): need to work out exact wildcard handling // TODO(stevvooe): need to work out exact wildcard handling
return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errdefs.ErrInvalidArgument) return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errInvalidArgument)
} }
parts := strings.Split(specifier, "/") parts := strings.Split(specifier, "/")
for _, part := range parts { for _, part := range parts {
if !specifierRe.MatchString(part) { if !specifierRe.MatchString(part) {
return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errdefs.ErrInvalidArgument) return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errInvalidArgument)
} }
} }
@ -229,7 +226,7 @@ func Parse(specifier string) (specs.Platform, error) {
return p, nil return p, nil
} }
return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errdefs.ErrInvalidArgument) return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument)
case 2: case 2:
// In this case, we treat as a regular os/arch pair. We don't care // In this case, we treat as a regular os/arch pair. We don't care
// about whether or not we know of the platform. // about whether or not we know of the platform.
@ -259,7 +256,7 @@ func Parse(specifier string) (specs.Platform, error) {
return p, nil return p, nil
} }
return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errdefs.ErrInvalidArgument) return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errInvalidArgument)
} }
// MustParse is like Parses but panics if the specifier cannot be parsed. // MustParse is like Parses but panics if the specifier cannot be parsed.
@ -291,30 +288,3 @@ func Normalize(platform specs.Platform) specs.Platform {
return platform return platform
} }
// ToProto converts from a slice of [Platform] to a slice of
// the protobuf definition [types.Platform].
func ToProto(platforms []Platform) []*types.Platform {
ap := make([]*types.Platform, len(platforms))
for i := range platforms {
p := types.Platform{
OS: platforms[i].OS,
Architecture: platforms[i].Architecture,
Variant: platforms[i].Variant,
}
ap[i] = &p
}
return ap
}
// FromProto converts a slice of the protobuf definition [types.Platform]
// to a slice of [Platform].
func FromProto(platforms []*types.Platform) []Platform {
op := make([]Platform, len(platforms))
for i := range platforms {
op[i].OS = platforms[i].OS
op[i].Architecture = platforms[i].Architecture
op[i].Variant = platforms[i].Variant
}
return op
}

View File

@ -24,9 +24,9 @@ import (
"sync" "sync"
api "github.com/containerd/containerd/api/services/introspection/v1" api "github.com/containerd/containerd/api/services/introspection/v1"
"github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/filters" "github.com/containerd/containerd/filters"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin"
ptypes "github.com/containerd/containerd/protobuf/types" ptypes "github.com/containerd/containerd/protobuf/types"
"github.com/containerd/containerd/services" "github.com/containerd/containerd/services"
@ -222,7 +222,7 @@ func pluginsToPB(plugins []*plugin.Plugin) []*api.Plugin {
Type: p.Registration.Type.String(), Type: p.Registration.Type.String(),
ID: p.Registration.ID, ID: p.Registration.ID,
Requires: requires, Requires: requires,
Platforms: platforms.ToProto(p.Meta.Platforms), Platforms: types.OCIPlatformToProto(p.Meta.Platforms),
Capabilities: p.Meta.Capabilities, Capabilities: p.Meta.Capabilities,
Exports: p.Meta.Exports, Exports: p.Meta.Exports,
InitErr: initErr, InitErr: initErr,