diff --git a/docs/cluster_spec.md b/docs/cluster_spec.md index 32dcdf6c7f..0fe0d87717 100644 --- a/docs/cluster_spec.md +++ b/docs/cluster_spec.md @@ -1229,6 +1229,30 @@ tar tf cri-containerd-cni-1.4.4-linux-amd64.tar.gz usr/local/sbin/runc ``` +### Runc Version and Packages +{{ kops_feature_table(kops_added_default='1.24.2') }} + +kOps uses the binaries from https://github.com/opencontainers/runc for installing runc on any supported OS. This makes it easy to specify the desired release version: + +```yaml +spec: + containerd: + runc: + version: 1.1.2 +``` + +It also makes it possible to use a newer version than the kOps binary, pre-release packages, or even a custom build, by specifying its URL and sha256: + +```yaml +spec: + containerd: + runc: + version: 1.100.0 + packages: + urlAmd64: https://cdn.example.com/k8s/runc/releases/download/v1.100.0/runc.amd64 + hashAmd64: ab1c67fbcbdddbe481e48a55cf0ef9a86b38b166b5079e0010737fd87d7454bb +``` + ### Registry Mirrors {{ kops_feature_table(kops_added_default='1.19') }} diff --git a/k8s/crds/kops.k8s.io_clusters.yaml b/k8s/crds/kops.k8s.io_clusters.yaml index 1f06750e07..480554175e 100644 --- a/k8s/crds/kops.k8s.io_clusters.yaml +++ b/k8s/crds/kops.k8s.io_clusters.yaml @@ -790,6 +790,33 @@ spec: root: description: Root directory for persistent data (default "/var/lib/containerd"). type: string + runc: + description: Runc configures the runc runtime. + properties: + packages: + description: Packages overrides the URL and hash for the packages. + properties: + hashAmd64: + description: HashAmd64 overrides the hash for the AMD64 + package. + type: string + hashArm64: + description: HashArm64 overrides the hash for the ARM64 + package. + type: string + urlAmd64: + description: UrlAmd64 overrides the URL for the AMD64 + package. + type: string + urlArm64: + description: UrlArm64 overrides the URL for the ARM64 + package. + type: string + type: object + version: + description: Version used to pick the runc package. + type: string + type: object skipInstall: description: SkipInstall prevents kOps from installing and modifying containerd in any way (default "false"). diff --git a/k8s/crds/kops.k8s.io_instancegroups.yaml b/k8s/crds/kops.k8s.io_instancegroups.yaml index dfc0aa78ff..ebaeaf2b8d 100644 --- a/k8s/crds/kops.k8s.io_instancegroups.yaml +++ b/k8s/crds/kops.k8s.io_instancegroups.yaml @@ -155,6 +155,33 @@ spec: root: description: Root directory for persistent data (default "/var/lib/containerd"). type: string + runc: + description: Runc configures the runc runtime. + properties: + packages: + description: Packages overrides the URL and hash for the packages. + properties: + hashAmd64: + description: HashAmd64 overrides the hash for the AMD64 + package. + type: string + hashArm64: + description: HashArm64 overrides the hash for the ARM64 + package. + type: string + urlAmd64: + description: UrlAmd64 overrides the URL for the AMD64 + package. + type: string + urlArm64: + description: UrlArm64 overrides the URL for the ARM64 + package. + type: string + type: object + version: + description: Version used to pick the runc package. + type: string + type: object skipInstall: description: SkipInstall prevents kOps from installing and modifying containerd in any way (default "false"). diff --git a/pkg/apis/kops/containerdconfig.go b/pkg/apis/kops/containerdconfig.go index 61e472383e..b4eb05ec6a 100644 --- a/pkg/apis/kops/containerdconfig.go +++ b/pkg/apis/kops/containerdconfig.go @@ -41,6 +41,8 @@ type ContainerdConfig struct { Version *string `json:"version,omitempty"` // NvidiaGPU configures the Nvidia GPU runtime. NvidiaGPU *NvidiaGPUConfig `json:"nvidiaGPU,omitempty"` + // Runc configures the runc runtime. + Runc *Runc `json:"runc,omitempty"` } type NvidiaGPUConfig struct { @@ -51,3 +53,10 @@ type NvidiaGPUConfig struct { // They will only be installed on intances that has an Nvidia GPU. Enabled *bool `json:"enabled,omitempty"` } + +type Runc struct { + // Version used to pick the runc package. + Version *string `json:"version,omitempty"` + // Packages overrides the URL and hash for the packages. + Packages *PackagesConfig `json:"packages,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha2/containerdconfig.go b/pkg/apis/kops/v1alpha2/containerdconfig.go index b1396a8a26..b41a58b06f 100644 --- a/pkg/apis/kops/v1alpha2/containerdconfig.go +++ b/pkg/apis/kops/v1alpha2/containerdconfig.go @@ -38,6 +38,8 @@ type ContainerdConfig struct { Version *string `json:"version,omitempty"` // NvidiaGPU configures the Nvidia GPU runtime. NvidiaGPU *NvidiaGPUConfig `json:"nvidiaGPU,omitempty"` + // Runc configures the runc runtime. + Runc *Runc `json:"runc,omitempty"` } type NvidiaGPUConfig struct { @@ -48,3 +50,10 @@ type NvidiaGPUConfig struct { // They will only be installed on intances that has an Nvidia GPU. Enabled *bool `json:"enabled,omitempty"` } + +type Runc struct { + // Version used to pick the runc package. + Version *string `json:"version,omitempty"` + // Packages overrides the URL and hash for the packages. + Packages *PackagesConfig `json:"packages,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go index bdac1d56d3..7c97eee7a2 100644 --- a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go @@ -1044,6 +1044,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*Runc)(nil), (*kops.Runc)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_Runc_To_kops_Runc(a.(*Runc), b.(*kops.Runc), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*kops.Runc)(nil), (*Runc)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_kops_Runc_To_v1alpha2_Runc(a.(*kops.Runc), b.(*Runc), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*SSHCredential)(nil), (*kops.SSHCredential)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha2_SSHCredential_To_kops_SSHCredential(a.(*SSHCredential), b.(*kops.SSHCredential), scope) }); err != nil { @@ -3322,6 +3332,15 @@ func autoConvert_v1alpha2_ContainerdConfig_To_kops_ContainerdConfig(in *Containe } else { out.NvidiaGPU = nil } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(kops.Runc) + if err := Convert_v1alpha2_Runc_To_kops_Runc(*in, *out, s); err != nil { + return err + } + } else { + out.Runc = nil + } return nil } @@ -3357,6 +3376,15 @@ func autoConvert_kops_ContainerdConfig_To_v1alpha2_ContainerdConfig(in *kops.Con } else { out.NvidiaGPU = nil } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(Runc) + if err := Convert_kops_Runc_To_v1alpha2_Runc(*in, *out, s); err != nil { + return err + } + } else { + out.Runc = nil + } return nil } @@ -6934,6 +6962,44 @@ func Convert_kops_RouteSpec_To_v1alpha2_RouteSpec(in *kops.RouteSpec, out *Route return autoConvert_kops_RouteSpec_To_v1alpha2_RouteSpec(in, out, s) } +func autoConvert_v1alpha2_Runc_To_kops_Runc(in *Runc, out *kops.Runc, s conversion.Scope) error { + out.Version = in.Version + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(kops.PackagesConfig) + if err := Convert_v1alpha2_PackagesConfig_To_kops_PackagesConfig(*in, *out, s); err != nil { + return err + } + } else { + out.Packages = nil + } + return nil +} + +// Convert_v1alpha2_Runc_To_kops_Runc is an autogenerated conversion function. +func Convert_v1alpha2_Runc_To_kops_Runc(in *Runc, out *kops.Runc, s conversion.Scope) error { + return autoConvert_v1alpha2_Runc_To_kops_Runc(in, out, s) +} + +func autoConvert_kops_Runc_To_v1alpha2_Runc(in *kops.Runc, out *Runc, s conversion.Scope) error { + out.Version = in.Version + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(PackagesConfig) + if err := Convert_kops_PackagesConfig_To_v1alpha2_PackagesConfig(*in, *out, s); err != nil { + return err + } + } else { + out.Packages = nil + } + return nil +} + +// Convert_kops_Runc_To_v1alpha2_Runc is an autogenerated conversion function. +func Convert_kops_Runc_To_v1alpha2_Runc(in *kops.Runc, out *Runc, s conversion.Scope) error { + return autoConvert_kops_Runc_To_v1alpha2_Runc(in, out, s) +} + func autoConvert_v1alpha2_SSHCredential_To_kops_SSHCredential(in *SSHCredential, out *kops.SSHCredential, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha2_SSHCredentialSpec_To_kops_SSHCredentialSpec(&in.Spec, &out.Spec, s); err != nil { diff --git a/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go index 24c9ea9673..bea2ed15b8 100644 --- a/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/kops/v1alpha2/zz_generated.deepcopy.go @@ -1412,6 +1412,11 @@ func (in *ContainerdConfig) DeepCopyInto(out *ContainerdConfig) { *out = new(NvidiaGPUConfig) (*in).DeepCopyInto(*out) } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(Runc) + (*in).DeepCopyInto(*out) + } return } @@ -4992,6 +4997,32 @@ func (in *RouteSpec) DeepCopy() *RouteSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Runc) DeepCopyInto(out *Runc) { + *out = *in + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(PackagesConfig) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Runc. +func (in *Runc) DeepCopy() *Runc { + if in == nil { + return nil + } + out := new(Runc) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SSHCredential) DeepCopyInto(out *SSHCredential) { *out = *in diff --git a/pkg/apis/kops/v1alpha3/containerdconfig.go b/pkg/apis/kops/v1alpha3/containerdconfig.go index 640d2fa193..7a9f64571a 100644 --- a/pkg/apis/kops/v1alpha3/containerdconfig.go +++ b/pkg/apis/kops/v1alpha3/containerdconfig.go @@ -38,6 +38,8 @@ type ContainerdConfig struct { Version *string `json:"version,omitempty"` // NvidiaGPU configures the Nvidia GPU runtime. NvidiaGPU *NvidiaGPUConfig `json:"nvidiaGPU,omitempty"` + // Runc configures the runc runtime. + Runc *Runc `json:"runc,omitempty"` } type NvidiaGPUConfig struct { @@ -48,3 +50,10 @@ type NvidiaGPUConfig struct { // They will only be installed on intances that has an Nvidia GPU. Enabled *bool `json:"enabled,omitempty"` } + +type Runc struct { + // Version used to pick the runc package. + Version *string `json:"version,omitempty"` + // Packages overrides the URL and hash for the packages. + Packages *PackagesConfig `json:"packages,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha3/zz_generated.conversion.go b/pkg/apis/kops/v1alpha3/zz_generated.conversion.go index 4698d0c227..ec616a1e21 100644 --- a/pkg/apis/kops/v1alpha3/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha3/zz_generated.conversion.go @@ -1084,6 +1084,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*Runc)(nil), (*kops.Runc)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha3_Runc_To_kops_Runc(a.(*Runc), b.(*kops.Runc), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*kops.Runc)(nil), (*Runc)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_kops_Runc_To_v1alpha3_Runc(a.(*kops.Runc), b.(*Runc), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*SSHCredential)(nil), (*kops.SSHCredential)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_SSHCredential_To_kops_SSHCredential(a.(*SSHCredential), b.(*kops.SSHCredential), scope) }); err != nil { @@ -3402,6 +3412,15 @@ func autoConvert_v1alpha3_ContainerdConfig_To_kops_ContainerdConfig(in *Containe } else { out.NvidiaGPU = nil } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(kops.Runc) + if err := Convert_v1alpha3_Runc_To_kops_Runc(*in, *out, s); err != nil { + return err + } + } else { + out.Runc = nil + } return nil } @@ -3437,6 +3456,15 @@ func autoConvert_kops_ContainerdConfig_To_v1alpha3_ContainerdConfig(in *kops.Con } else { out.NvidiaGPU = nil } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(Runc) + if err := Convert_kops_Runc_To_v1alpha3_Runc(*in, *out, s); err != nil { + return err + } + } else { + out.Runc = nil + } return nil } @@ -6911,6 +6939,44 @@ func Convert_kops_RouteSpec_To_v1alpha3_RouteSpec(in *kops.RouteSpec, out *Route return autoConvert_kops_RouteSpec_To_v1alpha3_RouteSpec(in, out, s) } +func autoConvert_v1alpha3_Runc_To_kops_Runc(in *Runc, out *kops.Runc, s conversion.Scope) error { + out.Version = in.Version + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(kops.PackagesConfig) + if err := Convert_v1alpha3_PackagesConfig_To_kops_PackagesConfig(*in, *out, s); err != nil { + return err + } + } else { + out.Packages = nil + } + return nil +} + +// Convert_v1alpha3_Runc_To_kops_Runc is an autogenerated conversion function. +func Convert_v1alpha3_Runc_To_kops_Runc(in *Runc, out *kops.Runc, s conversion.Scope) error { + return autoConvert_v1alpha3_Runc_To_kops_Runc(in, out, s) +} + +func autoConvert_kops_Runc_To_v1alpha3_Runc(in *kops.Runc, out *Runc, s conversion.Scope) error { + out.Version = in.Version + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(PackagesConfig) + if err := Convert_kops_PackagesConfig_To_v1alpha3_PackagesConfig(*in, *out, s); err != nil { + return err + } + } else { + out.Packages = nil + } + return nil +} + +// Convert_kops_Runc_To_v1alpha3_Runc is an autogenerated conversion function. +func Convert_kops_Runc_To_v1alpha3_Runc(in *kops.Runc, out *Runc, s conversion.Scope) error { + return autoConvert_kops_Runc_To_v1alpha3_Runc(in, out, s) +} + func autoConvert_v1alpha3_SSHCredential_To_kops_SSHCredential(in *SSHCredential, out *kops.SSHCredential, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha3_SSHCredentialSpec_To_kops_SSHCredentialSpec(&in.Spec, &out.Spec, s); err != nil { diff --git a/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go index 4306398b00..a44e268189 100644 --- a/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/kops/v1alpha3/zz_generated.deepcopy.go @@ -1375,6 +1375,11 @@ func (in *ContainerdConfig) DeepCopyInto(out *ContainerdConfig) { *out = new(NvidiaGPUConfig) (*in).DeepCopyInto(*out) } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(Runc) + (*in).DeepCopyInto(*out) + } return } @@ -4902,6 +4907,32 @@ func (in *RouteSpec) DeepCopy() *RouteSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Runc) DeepCopyInto(out *Runc) { + *out = *in + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(PackagesConfig) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Runc. +func (in *Runc) DeepCopy() *Runc { + if in == nil { + return nil + } + out := new(Runc) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SSHCredential) DeepCopyInto(out *SSHCredential) { *out = *in diff --git a/pkg/apis/kops/zz_generated.deepcopy.go b/pkg/apis/kops/zz_generated.deepcopy.go index a343750d5c..7be2b29cb0 100644 --- a/pkg/apis/kops/zz_generated.deepcopy.go +++ b/pkg/apis/kops/zz_generated.deepcopy.go @@ -1495,6 +1495,11 @@ func (in *ContainerdConfig) DeepCopyInto(out *ContainerdConfig) { *out = new(NvidiaGPUConfig) (*in).DeepCopyInto(*out) } + if in.Runc != nil { + in, out := &in.Runc, &out.Runc + *out = new(Runc) + (*in).DeepCopyInto(*out) + } return } @@ -5209,6 +5214,32 @@ func (in *RouteSpec) DeepCopy() *RouteSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Runc) DeepCopyInto(out *Runc) { + *out = *in + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } + if in.Packages != nil { + in, out := &in.Packages, &out.Packages + *out = new(PackagesConfig) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Runc. +func (in *Runc) DeepCopy() *Runc { + if in == nil { + return nil + } + out := new(Runc) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SSHCredential) DeepCopyInto(out *SSHCredential) { *out = *in diff --git a/pkg/model/components/containerd.go b/pkg/model/components/containerd.go index bbb25a2696..5a2937a9d1 100644 --- a/pkg/model/components/containerd.go +++ b/pkg/model/components/containerd.go @@ -48,6 +48,9 @@ func (b *ContainerdOptionsBuilder) BuildOptions(o interface{}) error { if fi.StringValue(containerd.Version) == "" { if b.IsKubernetesGTE("1.23") { containerd.Version = fi.String("1.6.6") + containerd.Runc = &kops.Runc{ + Version: fi.String("1.1.3"), + } } else { containerd.Version = fi.String("1.4.13") } diff --git a/upup/pkg/fi/cloudup/runc.go b/upup/pkg/fi/cloudup/runc.go index 03674eca59..7fc1cc57d0 100644 --- a/upup/pkg/fi/cloudup/runc.go +++ b/upup/pkg/fi/cloudup/runc.go @@ -30,27 +30,48 @@ import ( ) const ( - runcVersion = "1.1.3" runcVersionUrlAmd64 = "https://github.com/opencontainers/runc/releases/download/v%s/runc.amd64" runcVersionUrlArm64 = "https://github.com/opencontainers/runc/releases/download/v%s/runc.arm64" ) func findRuncAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*url.URL, *hashing.Hash, error) { - if c.Spec.Containerd == nil || c.Spec.Containerd.Version == nil { - return nil, nil, fmt.Errorf("unable to find containerd version, used to determine runc version") + if c.Spec.Containerd == nil { + return nil, nil, fmt.Errorf("unable to find containerd config") } + containerd := c.Spec.Containerd - containerdVersion, err := semver.ParseTolerant(fi.StringValue(c.Spec.Containerd.Version)) + containerdVersion, err := semver.ParseTolerant(fi.StringValue(containerd.Version)) if err != nil { - return nil, nil, fmt.Errorf("unable to parse version string: %q", fi.StringValue(c.Spec.Containerd.Version)) + return nil, nil, fmt.Errorf("unable to parse version string: %q", fi.StringValue(containerd.Version)) } - // The a compatible runc binary is bundled with containerd builds < v1.6.0 + // A compatible runc binary is bundled with containerd builds < v1.6.0 // https://github.com/containerd/containerd/issues/6541 if containerdVersion.LT(semver.MustParse("1.6.0")) { return nil, nil, nil } - version := runcVersion + if containerd.Runc == nil { + return nil, nil, fmt.Errorf("unable to find runc config") + } + runc := containerd.Runc + + if runc.Packages != nil { + if arch == architectures.ArchitectureAmd64 && runc.Packages.UrlAmd64 != nil && runc.Packages.HashAmd64 != nil { + assetUrl := fi.StringValue(runc.Packages.UrlAmd64) + assetHash := fi.StringValue(runc.Packages.HashAmd64) + return findAssetsUrlHash(assetBuilder, assetUrl, assetHash) + } + if arch == architectures.ArchitectureArm64 && runc.Packages.UrlArm64 != nil && runc.Packages.HashArm64 != nil { + assetUrl := fi.StringValue(runc.Packages.UrlArm64) + assetHash := fi.StringValue(runc.Packages.HashArm64) + return findAssetsUrlHash(assetBuilder, assetUrl, assetHash) + } + } + + version := fi.StringValue(runc.Version) + if version == "" { + return nil, nil, fmt.Errorf("unable to find runc version") + } assetUrl, assetHash, err := findRuncVersionUrlHash(arch, version) if err != nil { return nil, nil, err diff --git a/upup/pkg/fi/cloudup/runc_test.go b/upup/pkg/fi/cloudup/runc_test.go index 7f5dd58b8e..9726f5a550 100644 --- a/upup/pkg/fi/cloudup/runc_test.go +++ b/upup/pkg/fi/cloudup/runc_test.go @@ -17,12 +17,224 @@ limitations under the License. package cloudup import ( + "fmt" "os" + "reflect" "testing" "k8s.io/kops/util/pkg/architectures" ) +func TestRuncVersionUrlHash(t *testing.T) { + tests := []struct { + version string + arch architectures.Architecture + hash string + url string + err error + }{ + { + arch: architectures.ArchitectureAmd64, + version: "1.100.0", + url: "", + hash: "", + err: fmt.Errorf("unknown url and hash for runc version: amd64 - 1.100.0"), + }, + { + arch: architectures.ArchitectureArm64, + version: "1.100.0", + url: "", + hash: "", + err: fmt.Errorf("unknown url and hash for runc version: arm64 - 1.100.0"), + }, + { + arch: architectures.ArchitectureAmd64, + version: "1.1.0", + url: "https://github.com/opencontainers/runc/releases/download/v1.1.0/runc.amd64", + hash: "ab1c67fbcbdddbe481e48a55cf0ef9a86b38b166b5079e0010737fd87d7454bb", + err: nil, + }, + { + arch: architectures.ArchitectureArm64, + version: "1.1.0", + url: "https://github.com/opencontainers/runc/releases/download/v1.1.0/runc.arm64", + hash: "9ec8e68feabc4e7083a4cfa45ebe4d529467391e0b03ee7de7ddda5770b05e68", + err: nil, + }, + } + for _, test := range tests { + t.Run(fmt.Sprintf("%s-%s", test.version, test.arch), func(t *testing.T) { + url, hash, err := findRuncVersionUrlHash(test.arch, test.version) + if !reflect.DeepEqual(err, test.err) { + t.Errorf("actual error %q differs from expected error %q", err, test.err) + return + } + if url != test.url { + t.Errorf("actual url %q differs from expected url %q", url, test.url) + return + } + if hash != test.hash { + t.Errorf("actual hash %q differs from expected hash %q", hash, test.hash) + return + } + }) + } +} + +func TestRuncVersionUrl(t *testing.T) { + tests := []struct { + version string + arch architectures.Architecture + url string + err error + }{ + { + arch: "", + version: "1.1.0", + url: "", + err: fmt.Errorf("unknown arch: \"\""), + }, + { + arch: "arm", + version: "1.1.0", + url: "", + err: fmt.Errorf("unknown arch: \"arm\""), + }, + { + arch: architectures.ArchitectureAmd64, + version: "", + url: "", + err: fmt.Errorf("unable to parse version string: \"\""), + }, + { + arch: architectures.ArchitectureArm64, + version: "", + url: "", + err: fmt.Errorf("unable to parse version string: \"\""), + }, + { + arch: architectures.ArchitectureAmd64, + version: "1.0.0", + url: "", + err: fmt.Errorf("unsupported runc version: \"1.0.0\""), + }, + { + arch: architectures.ArchitectureArm64, + version: "1.0.0", + url: "", + err: fmt.Errorf("unsupported runc version: \"1.0.0\""), + }, + { + arch: architectures.ArchitectureAmd64, + version: "1.1.0", + url: "https://github.com/opencontainers/runc/releases/download/v1.1.0/runc.amd64", + err: nil, + }, + { + arch: architectures.ArchitectureArm64, + version: "1.1.0", + url: "https://github.com/opencontainers/runc/releases/download/v1.1.0/runc.arm64", + err: nil, + }, + } + for _, test := range tests { + t.Run(fmt.Sprintf("%s-%s", test.version, test.arch), func(t *testing.T) { + url, err := findRuncVersionUrl(test.arch, test.version) + if !reflect.DeepEqual(err, test.err) { + t.Errorf("actual error %q differs from expected error %q", err, test.err) + return + } + if url != test.url { + t.Errorf("actual url %q differs from expected url %q", url, test.url) + return + } + }) + } +} + +func TestRuncVersionHash(t *testing.T) { + tests := []struct { + version string + arch architectures.Architecture + hash string + err error + }{ + { + arch: "", + version: "1.1.0", + hash: "", + err: fmt.Errorf("unknown arch: \"\""), + }, + { + arch: "arm", + version: "1.1.0", + hash: "", + err: fmt.Errorf("unknown arch: \"arm\""), + }, + { + arch: architectures.ArchitectureAmd64, + version: "", + hash: "", + err: fmt.Errorf("unable to parse version string: \"\""), + }, + { + arch: architectures.ArchitectureArm64, + version: "", + hash: "", + err: fmt.Errorf("unable to parse version string: \"\""), + }, + { + arch: architectures.ArchitectureAmd64, + version: "1.0.0", + hash: "", + err: fmt.Errorf("unsupported runc version: \"1.0.0\""), + }, + { + arch: architectures.ArchitectureArm64, + version: "1.0.0", + hash: "", + err: fmt.Errorf("unsupported runc version: \"1.0.0\""), + }, + { + arch: architectures.ArchitectureAmd64, + version: "1.100.0", + hash: "", + err: fmt.Errorf("unknown hash for runc version: amd64 - 1.100.0"), + }, + { + arch: architectures.ArchitectureArm64, + version: "1.100.0", + hash: "", + err: fmt.Errorf("unknown hash for runc version: arm64 - 1.100.0"), + }, + { + arch: architectures.ArchitectureAmd64, + version: "1.1.0", + hash: "ab1c67fbcbdddbe481e48a55cf0ef9a86b38b166b5079e0010737fd87d7454bb", + err: nil, + }, + { + arch: architectures.ArchitectureArm64, + version: "1.1.0", + hash: "9ec8e68feabc4e7083a4cfa45ebe4d529467391e0b03ee7de7ddda5770b05e68", + err: nil, + }, + } + for _, test := range tests { + t.Run(fmt.Sprintf("%s-%s", test.version, test.arch), func(t *testing.T) { + hash, err := findRuncVersionHash(test.arch, test.version) + if !reflect.DeepEqual(err, test.err) { + t.Errorf("actual error %q differs from expected error %q", err, test.err) + return + } + if hash != test.hash { + t.Errorf("actual hash %q differs from expected hash %q", hash, test.hash) + return + } + }) + } +} + func TestRuncVersionsHashesAmd64(t *testing.T) { if os.Getenv("VERIFY_HASHES") == "" { t.Skip("VERIFY_HASHES not set, won't download & verify runc hashes")