platforms: remove errdefs dependency

This cleans up the platforms package from dependencies that are not strictly
needed. This is in preparation of making this package a separate module, which
can be shared by plugins, and containerd versions (as well as external consumers),

- Remove dependency on the errdefs package: most uses of these error
  definitions were used internally, and other errors may not be useful
  for external consumers as sentinel errors.
- ErrInvalidArgument may be a potential exception, although a look at
  current uses of this package shows that there's no special handling of
  invalid parameters vs other errors (all would boil down to "the passed
  platform is invalid" (either the format, or parsing is not implemented
  on a specific platform)
- Remove uses of the convenience "Platform" alias in favor of using the
  upstream (from OCI spec). Consumers of this package can still use the
  convenience alias, but make sure that function signatures do not imply
  that it's a different type (which can cause confusion).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2023-09-13 02:23:05 +02:00
parent 0f52935a53
commit 381442945b
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
5 changed files with 51 additions and 28 deletions

View File

@ -19,12 +19,12 @@ package platforms
import (
"bufio"
"bytes"
"errors"
"fmt"
"os"
"runtime"
"strings"
"github.com/containerd/containerd/errdefs"
"golang.org/x/sys/unix"
)
@ -70,7 +70,7 @@ func getCPUInfo(pattern string) (info string, err error) {
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
@ -83,7 +83,7 @@ func getCPUVariantFromArch(arch string) (string, error) {
if arch == "aarch64" {
variant = "8"
} else if arch[0:4] == "armv" && len(arch) >= 5 {
//Valid arch format is in form of armvXx
// Valid arch format is in form of armvXx
switch arch[3:5] {
case "v8":
variant = "8"
@ -101,7 +101,7 @@ func getCPUVariantFromArch(arch string) (string, error) {
variant = "unknown"
}
} 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
}
@ -112,11 +112,10 @@ func getCPUVariantFromArch(arch string) (string, error) {
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
// was not present.
func getCPUVariant() (string, error) {
variant, err := getCPUInfo("Cpu architecture")
if err != nil {
if errdefs.IsNotFound(err) {
//Let's try getting CPU variant from machine architecture
if errors.Is(err, errNotFound) {
// Let's try getting CPU variant from machine architecture
arch, err := getMachineArch()
if err != nil {
return "", fmt.Errorf("failure getting machine architecture: %v", err)

View File

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

View File

@ -21,8 +21,6 @@ package platforms
import (
"fmt"
"runtime"
"github.com/containerd/containerd/errdefs"
)
func getCPUVariant() (string, error) {
@ -49,10 +47,8 @@ func getCPUVariant() (string, error) {
default:
variant = "unknown"
}
} 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

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

@ -120,7 +120,6 @@ import (
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/errdefs"
)
var (
@ -186,14 +185,14 @@ func ParseAll(specifiers []string) ([]specs.Platform, error) {
func Parse(specifier string) (specs.Platform, error) {
if strings.Contains(specifier, "*") {
// 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, "/")
for _, part := range parts {
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 +228,7 @@ func Parse(specifier string) (specs.Platform, error) {
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:
// In this case, we treat as a regular os/arch pair. We don't care
// about whether or not we know of the platform.
@ -259,7 +258,7 @@ func Parse(specifier string) (specs.Platform, error) {
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.
@ -297,24 +296,25 @@ func Normalize(platform specs.Platform) specs.Platform {
func ToProto(platforms []Platform) []*types.Platform {
ap := make([]*types.Platform, len(platforms))
for i := range platforms {
p := types.Platform{
ap[i] = &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))
func FromProto(platforms []*types.Platform) []specs.Platform {
op := make([]specs.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
op[i] = specs.Platform{
OS: platforms[i].OS,
Architecture: platforms[i].Architecture,
Variant: platforms[i].Variant,
}
}
return op
}