diff --git a/client/kubernetes/cluster.go b/client/kubernetes/cluster.go new file mode 100644 index 00000000..33469250 --- /dev/null +++ b/client/kubernetes/cluster.go @@ -0,0 +1,135 @@ +package kubernetes + +import ( + "context" + "fmt" + + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/cluster" +) + +const ( + WorkflowWorkerNonTerminalStateIndex = ".status.state.nonTerminalWorker" + HardwareMACAddrIndex = ".spec.interfaces.dhcp.mac" + HardwareIPAddrIndex = ".spec.interfaces.dhcp.ip" +) + +// NewCluster returns a controller-runtime cluster.Cluster with the Tinkerbell runtime +// scheme registered, and indexers for: +// * Hardware by MAC address +// * Hardware by IP address +// * Workflows by worker address +// +// Callers must instantiate the client-side cache by calling Start() before use. +func NewCluster(config *rest.Config) (cluster.Cluster, error) { + runtimescheme := runtime.NewScheme() + + err := clientgoscheme.AddToScheme(runtimescheme) + if err != nil { + return nil, err + } + + err = v1alpha1.AddToScheme(runtimescheme) + if err != nil { + return nil, err + } + + c, err := cluster.New(config, func(o *cluster.Options) { + o.Scheme = runtimescheme + }) + + if err != nil { + return nil, err + } + indexers := []struct { + obj client.Object + field string + extractValue client.IndexerFunc + }{ + { + &v1alpha1.Workflow{}, + WorkflowWorkerNonTerminalStateIndex, + workflowWorkerNonTerminalStateIndexFunc, + }, + { + &v1alpha1.Hardware{}, + HardwareIPAddrIndex, + hardwareIPIndexFunc, + }, + { + &v1alpha1.Hardware{}, + HardwareMACAddrIndex, + hardwareMacIndexFunc, + }, + } + for _, indexer := range indexers { + if err := c.GetFieldIndexer().IndexField( + context.Background(), + indexer.obj, + indexer.field, + indexer.extractValue, + ); err != nil { + return nil, fmt.Errorf("failed to setup %s indexer, %w", indexer.field, err) + } + } + + return c, nil +} + +// TODO micahhausler: make the following index functions public in tinkerbell/tink import from there + +// workflowWorkerNonTerminalStateIndexFunc func indexes workflow by worker for non terminal workflows. +func workflowWorkerNonTerminalStateIndexFunc(obj client.Object) []string { + wf, ok := obj.(*v1alpha1.Workflow) + if !ok { + return nil + } + + resp := []string{} + if !(wf.Status.State == v1alpha1.WorkflowStateRunning || wf.Status.State == v1alpha1.WorkflowStatePending) { + return resp + } + for _, task := range wf.Status.Tasks { + if task.WorkerAddr != "" { + resp = append(resp, task.WorkerAddr) + } + } + + return resp +} + +// hardwareMacIndexFunc returns a list of mac addresses from a hardware. +func hardwareMacIndexFunc(obj client.Object) []string { + hw, ok := obj.(*v1alpha1.Hardware) + if !ok { + return nil + } + resp := []string{} + for _, iface := range hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.MAC != "" { + resp = append(resp, iface.DHCP.MAC) + } + } + + return resp +} + +// hardwareIPIndexFunc returns a list of mac addresses from a hardware. +func hardwareIPIndexFunc(obj client.Object) []string { + hw, ok := obj.(*v1alpha1.Hardware) + if !ok { + return nil + } + resp := []string{} + for _, iface := range hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.IP != nil && iface.DHCP.IP.Address != "" { + resp = append(resp, iface.DHCP.IP.Address) + } + } + + return resp +} diff --git a/client/kubernetes/hardware_finder.go b/client/kubernetes/hardware_finder.go new file mode 100644 index 00000000..036874fd --- /dev/null +++ b/client/kubernetes/hardware_finder.go @@ -0,0 +1,137 @@ +package kubernetes + +import ( + "context" + "net" + + "github.com/packethost/pkg/log" + "github.com/pkg/errors" + "github.com/tinkerbell/boots/client" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "github.com/tinkerbell/tink/pkg/controllers" + "github.com/tinkerbell/tink/pkg/convert" + "github.com/tinkerbell/tink/protos/workflow" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + crclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Finder is a type that looks up hardware and workflows from Kubernetes +type Finder struct { + clientFunc func() crclient.Client + cacheStarter func(context.Context) error + logger log.Logger + namespace string +} + +// NewFinder returns a HardwareFinder that discovers hardware from Kubernetes. +// +// Callers must instantiate the client-side cache by calling Start() before use. +func NewFinder(logger log.Logger, k8sAPI, kubeconfig string) (*Finder, error) { + ccfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, + &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: k8sAPI}}) + + config, err := ccfg.ClientConfig() + if err != nil { + return nil, err + } + + namespace, _, err := ccfg.Namespace() + if err != nil { + return nil, errors.WithStack(err) + } + + cluster, err := NewCluster(config) + if err != nil { + return nil, errors.WithStack(err) + } + + return &Finder{ + clientFunc: cluster.GetClient, + cacheStarter: cluster.Start, + logger: logger, + namespace: namespace, + }, nil +} + +// Start instantiates the client-side cache +func (f *Finder) Start(ctx context.Context) error { + return f.cacheStarter(ctx) +} + +// ByIP returns a Discoverer for a particular IP. +func (f *Finder) ByIP(ctx context.Context, ip net.IP) (client.Discoverer, error) { + hardwareList := &v1alpha1.HardwareList{} + + err := f.clientFunc().List(ctx, hardwareList, &crclient.MatchingFields{ + controllers.HardwareIPAddrIndex: ip.String(), + }) + if err != nil { + return nil, errors.Wrap(err, "failed listing hardware") + } + + if len(hardwareList.Items) == 0 { + return nil, errors.New("no hardware found") + } + + if len(hardwareList.Items) > 1 { + return nil, errors.Errorf("got %d hardware for ip %s, expected only 1", len(hardwareList.Items), ip) + } + + return NewK8sDiscoverer(&hardwareList.Items[0]), nil +} + +// ByMAC returns a Discoverer for a particular MAC address. +func (f *Finder) ByMAC(ctx context.Context, mac net.HardwareAddr, _ net.IP, _ string) (client.Discoverer, error) { + hardwareList := &v1alpha1.HardwareList{} + + err := f.clientFunc().List(ctx, hardwareList, &crclient.MatchingFields{ + controllers.HardwareMACAddrIndex: mac.String(), + }) + if err != nil { + return nil, errors.Wrap(err, "failed listing hardware") + } + + if len(hardwareList.Items) == 0 { + return nil, errors.New("no hardware found") + } + + if len(hardwareList.Items) > 1 { + return nil, errors.Errorf("got %d hardware for mac %s, expected only 1", len(hardwareList.Items), mac) + } + + return NewK8sDiscoverer(&hardwareList.Items[0]), nil +} + +// HasActiveWorkflow finds if an active workflow exists for a particular hardware ID. +func (f *Finder) HasActiveWorkflow(ctx context.Context, hwID client.HardwareID) (bool, error) { + if hwID == "" { + return false, errors.New("missing hardware id") + } + + stored := &v1alpha1.WorkflowList{} + err := f.clientFunc().List(ctx, stored, &crclient.MatchingFields{ + controllers.WorkflowWorkerNonTerminalStateIndex: hwID.String(), + }) + if err != nil { + return false, errors.Wrap(err, "failed to list workflows") + } + + wfContexts := []*workflow.WorkflowContext{} + for _, wf := range stored.Items { + wfContexts = append(wfContexts, convert.WorkflowToWorkflowContext(&wf)) + } + + wcl := &workflow.WorkflowContextList{ + WorkflowContexts: wfContexts, + } + + for _, wf := range (*wcl).WorkflowContexts { + if wf.CurrentActionState == workflow.State_STATE_PENDING || wf.CurrentActionState == workflow.State_STATE_RUNNING { + return true, nil + } + } + + return false, nil +} diff --git a/client/kubernetes/k8s_models.go b/client/kubernetes/k8s_models.go new file mode 100644 index 00000000..dbb88630 --- /dev/null +++ b/client/kubernetes/k8s_models.go @@ -0,0 +1,341 @@ +package kubernetes + +import ( + "net" + "time" + + "github.com/tinkerbell/boots/client" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" +) + +func tinkOsToDiscovererOS(in *v1alpha1.MetadataInstanceOperatingSystem) *client.OperatingSystem { + if in == nil { + return nil + } + + return &client.OperatingSystem{ + Slug: in.Slug, + Distro: in.Distro, + Version: in.Version, + ImageTag: in.ImageTag, + OsSlug: in.OsSlug, + } +} + +func tinkIpToDiscovererIp(in *v1alpha1.MetadataInstanceIP) *client.IP { + if in == nil { + return nil + } + + return &client.IP{ + Address: net.ParseIP(in.Address), + Netmask: net.ParseIP(in.Netmask), + Gateway: net.ParseIP(in.Gateway), + Family: int(in.Family), + Public: in.Public, + Management: in.Management, + } +} + +func (d *K8sDiscoverer) Instance() *client.Instance { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Instance != nil { + return &client.Instance{ + ID: d.hw.Spec.Metadata.Instance.ID, + State: client.InstanceState(d.hw.Spec.Metadata.Instance.State), + Hostname: d.hw.Spec.Metadata.Instance.Hostname, + AllowPXE: d.hw.Spec.Metadata.Instance.AllowPxe, + Rescue: d.hw.Spec.Metadata.Instance.Rescue, + OS: tinkOsToDiscovererOS(d.hw.Spec.Metadata.Instance.OperatingSystem), + AlwaysPXE: d.hw.Spec.Metadata.Instance.AlwaysPxe, + IPXEScriptURL: d.hw.Spec.Metadata.Instance.IpxeScriptURL, + IPs: func(in []*v1alpha1.MetadataInstanceIP) []client.IP { + resp := []client.IP{} + for _, ip := range in { + resp = append(resp, *tinkIpToDiscovererIp(ip)) + } + + return resp + }(d.hw.Spec.Metadata.Instance.Ips), + UserData: d.hw.Spec.Metadata.Instance.Userdata, + CryptedRootPassword: d.hw.Spec.Metadata.Instance.CryptedRootPassword, + Tags: d.hw.Spec.Metadata.Instance.Tags, + SSHKeys: d.hw.Spec.Metadata.Instance.SSHKeys, + NetworkReady: d.hw.Spec.Metadata.Instance.NetworkReady, + } + } + + return nil +} + +func (d *K8sDiscoverer) MAC() net.HardwareAddr { + if len(d.hw.Spec.Interfaces) > 0 && d.hw.Spec.Interfaces[0].DHCP != nil { + mac, err := net.ParseMAC(d.hw.Spec.Interfaces[0].DHCP.MAC) + if err != nil { + return nil + } + + return mac + } + + return nil +} + +func (d *K8sDiscoverer) Mode() string { + + return "hardware" +} + +func (d *K8sDiscoverer) GetIP(addr net.HardwareAddr) client.IP { + for _, iface := range d.hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.MAC != "" && iface.DHCP.IP != nil { + if addr.String() == iface.DHCP.MAC { + return client.IP{ + Address: net.ParseIP(iface.DHCP.IP.Address), + Netmask: net.ParseIP(iface.DHCP.IP.Netmask), + Gateway: net.ParseIP(iface.DHCP.IP.Gateway), + Family: int(iface.DHCP.IP.Family), + // TODO not 100% accurate + Public: !net.ParseIP(iface.DHCP.IP.Address).IsPrivate(), + // TODO: When should we set this to true? + Management: false, + } + } + } + } + + return client.IP{} +} + +func (d *K8sDiscoverer) GetMAC(ip net.IP) net.HardwareAddr { + for _, iface := range d.hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.MAC != "" && iface.DHCP.IP != nil { + if ip.String() == iface.DHCP.IP.Address { + mac, err := net.ParseMAC(iface.DHCP.MAC) + if err != nil { + return nil + } + + return mac + } + } + } + + return nil +} + +func (d *K8sDiscoverer) DnsServers(mac net.HardwareAddr) []net.IP { + resp := []net.IP{} + for _, iface := range d.hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.MAC != "" { + for _, ns := range iface.DHCP.NameServers { + resp = append(resp, net.ParseIP(ns)) + } + } + } + + return resp +} + +func (d *K8sDiscoverer) LeaseTime(mac net.HardwareAddr) time.Duration { + if len(d.hw.Spec.Interfaces) > 0 && d.hw.Spec.Interfaces[0].DHCP != nil { + return time.Duration(d.hw.Spec.Interfaces[0].DHCP.LeaseTime) * time.Second + } + // Default to 24 hours? + + return time.Hour * 24 +} + +func (d *K8sDiscoverer) Hostname() (string, error) { + for _, iface := range d.hw.Spec.Interfaces { + if iface.DHCP != nil && iface.DHCP.Hostname != "" { + return iface.DHCP.Hostname, nil + } + } + + return "", nil +} + +func (d *K8sDiscoverer) Hardware() client.Hardware { return d } + +func (d *K8sDiscoverer) SetMAC(mac net.HardwareAddr) {} + +func NewK8sDiscoverer(hw *v1alpha1.Hardware) client.Discoverer { + + return &K8sDiscoverer{hw: hw} +} + +type K8sDiscoverer struct { + hw *v1alpha1.Hardware +} + +var _ client.Discoverer = &K8sDiscoverer{} +var _ client.Hardware = &K8sDiscoverer{} + +func (d *K8sDiscoverer) HardwareAllowWorkflow(mac net.HardwareAddr) bool { + for _, iface := range d.hw.Spec.Interfaces { + if iface.Netboot != nil && iface.DHCP != nil && mac.String() == iface.DHCP.MAC { + return *iface.Netboot.AllowWorkflow + } + } + + return false +} + +func (d *K8sDiscoverer) HardwareAllowPXE(mac net.HardwareAddr) bool { + for _, iface := range d.hw.Spec.Interfaces { + if iface.Netboot != nil && iface.DHCP != nil && mac.String() == iface.DHCP.MAC { + return *iface.Netboot.AllowPXE + } + } + + return false +} + +func (d *K8sDiscoverer) HardwareArch(mac net.HardwareAddr) string { + for _, iface := range d.hw.Spec.Interfaces { + if iface.DHCP != nil { + return iface.DHCP.Arch + } + } + + return "" +} + +func (d *K8sDiscoverer) HardwareBondingMode() client.BondingMode { + if d.hw.Spec.Metadata != nil { + return client.BondingMode(d.hw.Spec.Metadata.BondingMode) + } + + return client.BondingMode(0) +} + +func (d *K8sDiscoverer) HardwareFacilityCode() string { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Facility != nil { + return d.hw.Spec.Metadata.Facility.FacilityCode + } + + return "" +} + +func (d *K8sDiscoverer) HardwareID() client.HardwareID { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Instance != nil { + return client.HardwareID(d.hw.Spec.Metadata.Instance.ID) + } + + return client.HardwareID("") +} + +func (d *K8sDiscoverer) HardwareIPs() []client.IP { + resp := []client.IP{} + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Instance != nil { + for _, ip := range d.hw.Spec.Metadata.Instance.Ips { + resp = append(resp, *tinkIpToDiscovererIp(ip)) + } + } + + return resp +} + +func (d *K8sDiscoverer) Interfaces() []client.Port { return nil } + +func (d *K8sDiscoverer) HardwareManufacturer() string { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Manufacturer != nil { + return d.hw.Spec.Metadata.Manufacturer.ID + } + + return "" +} + +func (d *K8sDiscoverer) HardwareProvisioner() string { + + return "" +} + +func (d *K8sDiscoverer) HardwarePlanSlug() string { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Facility != nil { + return d.hw.Spec.Metadata.Facility.PlanSlug + } + + return "" +} + +func (d *K8sDiscoverer) HardwarePlanVersionSlug() string { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Facility != nil { + return d.hw.Spec.Metadata.Facility.PlanVersionSlug + } + + return "" +} + +func (d *K8sDiscoverer) HardwareState() client.HardwareState { + if d.hw.Spec.Metadata != nil { + return client.HardwareState(d.hw.Spec.Metadata.State) + } + + return "" +} + +func (d *K8sDiscoverer) HardwareOSIEVersion() string { + + return "" +} + +func (d *K8sDiscoverer) HardwareUEFI(mac net.HardwareAddr) bool { + for _, iface := range d.hw.Spec.Interfaces { + if iface.DHCP != nil { + return iface.DHCP.UEFI + } + } + + return false +} + +func (d *K8sDiscoverer) OSIEBaseURL(mac net.HardwareAddr) string { + for _, iface := range d.hw.Spec.Interfaces { + if iface.Netboot != nil && iface.Netboot.OSIE != nil { + return iface.Netboot.OSIE.BaseURL + } + } + + return "" +} + +func (d *K8sDiscoverer) KernelPath(mac net.HardwareAddr) string { + for _, iface := range d.hw.Spec.Interfaces { + if iface.Netboot != nil && iface.Netboot.OSIE != nil { + return iface.Netboot.OSIE.Kernel + } + } + + return "" +} + +func (d *K8sDiscoverer) InitrdPath(mac net.HardwareAddr) string { + for _, iface := range d.hw.Spec.Interfaces { + if iface.Netboot != nil && iface.Netboot.OSIE != nil { + return iface.Netboot.OSIE.Initrd + } + } + + return "" +} + +func (d *K8sDiscoverer) OperatingSystem() *client.OperatingSystem { + if d.hw.Spec.Metadata != nil && d.hw.Spec.Metadata.Instance != nil && d.hw.Spec.Metadata.Instance.OperatingSystem != nil { + return &client.OperatingSystem{ + Slug: d.hw.Spec.Metadata.Instance.OperatingSystem.Slug, + Distro: d.hw.Spec.Metadata.Instance.OperatingSystem.Distro, + Version: d.hw.Spec.Metadata.Instance.OperatingSystem.Version, + ImageTag: d.hw.Spec.Metadata.Instance.OperatingSystem.ImageTag, + OsSlug: d.hw.Spec.Metadata.Instance.OperatingSystem.OsSlug, + } + } + + return nil +} + +// GetTraceparent always returns an empty string. +func (d *K8sDiscoverer) GetTraceparent() string { + + return "" +} diff --git a/client/kubernetes/k8s_models_test.go b/client/kubernetes/k8s_models_test.go new file mode 100644 index 00000000..754a3fe8 --- /dev/null +++ b/client/kubernetes/k8s_models_test.go @@ -0,0 +1,129 @@ +package kubernetes + +import ( + "net" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/tinkerbell/boots/client" + "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestInstance(t *testing.T) { + cases := []struct { + name string + input *v1alpha1.Hardware + want *client.Instance + }{ + { + name: "nil metadata", + input: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.HardwareSpec{ + Metadata: nil, // intentionally nil + }, + Status: v1alpha1.HardwareStatus{}, + }, + want: nil, + }, + { + name: "nil metadata instance", + input: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{}, + Metadata: &v1alpha1.HardwareMetadata{ + Instance: nil, + }, + }, + Status: v1alpha1.HardwareStatus{}, + }, + want: nil, + }, + { + name: "real hardware", + input: &v1alpha1.Hardware{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.HardwareSpec{ + Interfaces: []v1alpha1.Interface{}, + Metadata: &v1alpha1.HardwareMetadata{ + State: "", + BondingMode: 0, + Manufacturer: &v1alpha1.MetadataManufacturer{ + ID: "", + Slug: "", + }, + Instance: &v1alpha1.MetadataInstance{ + ID: "i-abcdef", + State: "active", + Hostname: "ip-1-2-3-4.dns.local", + AllowPxe: true, + Rescue: false, + OperatingSystem: &v1alpha1.MetadataInstanceOperatingSystem{ + Distro: "ubuntu", + Version: "20.04", + OsSlug: "ubuntu_20_04", + }, + AlwaysPxe: false, + IpxeScriptURL: "http://mumble.mumble.pxe/os", + Ips: []*v1alpha1.MetadataInstanceIP{ + { + Address: "172.16.10.100", + Netmask: "255.255.255.0", + Gateway: "172.16.10.1", + Family: 4, + Public: false, + Management: false, + }, + }, + Userdata: "", + CryptedRootPassword: "", + Tags: []string{}, + Storage: &v1alpha1.MetadataInstanceStorage{}, + SSHKeys: []string{}, + NetworkReady: false, + }, + Custom: &v1alpha1.MetadataCustom{}, + Facility: &v1alpha1.MetadataFacility{}, + }, + TinkVersion: 0, + Disks: []v1alpha1.Disk{}, + }, + Status: v1alpha1.HardwareStatus{}, + }, + want: &client.Instance{ + ID: "i-abcdef", + State: "active", + Hostname: "ip-1-2-3-4.dns.local", + AllowPXE: true, + OS: &client.OperatingSystem{Distro: "ubuntu", Version: "20.04", OsSlug: "ubuntu_20_04"}, + IPXEScriptURL: "http://mumble.mumble.pxe/os", + IPs: []client.IP{ + { + Address: net.ParseIP("172.16.10.100"), + Netmask: net.ParseIP("255.255.255.0"), + Gateway: net.ParseIP("172.16.10.1"), + Family: 4, + }, + }, + Tags: []string{}, + SSHKeys: []string{}, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + d := NewK8sDiscoverer(tc.input) + got := d.Instance() + if diff := cmp.Diff(got, tc.want, cmpopts.IgnoreUnexported(client.Instance{})); diff != "" { + t.Fatal(diff) + } + }) + } +} diff --git a/client/noop_workflow_finder.go b/client/noop_workflow_finder.go new file mode 100644 index 00000000..5fa76185 --- /dev/null +++ b/client/noop_workflow_finder.go @@ -0,0 +1,11 @@ +package client + +import "context" + +// NoOpWokrflowFinder is used to always return false. This is used when no workflow engine applies. +type NoOpWorkflowFinder struct{} + +// HasActiveWorkflow always returns false without error +func (f *NoOpWorkflowFinder) HasActiveWorkflow(context.Context, HardwareID) (bool, error) { + return false, nil +} diff --git a/client/tinkerbell/hardware_finder.go b/client/tinkerbell/hardware_finder.go index b2600139..7cf8ba44 100644 --- a/client/tinkerbell/hardware_finder.go +++ b/client/tinkerbell/hardware_finder.go @@ -82,20 +82,12 @@ func (f *HardwareFinder) ByMAC(ctx context.Context, mac net.HardwareAddr, _ net. return d, nil } -// NoOpWokrflowFinder is used to always return false. -type NoOpWorkflowFinder struct{} - -// HasActiveWorkflow always returns false without error -func (f *NoOpWorkflowFinder) HasActiveWorkflow(context.Context, client.HardwareID) (bool, error) { - return false, nil -} - // WorkflowFinder is a type for finding if a hardware ID has active workflows. type WorkflowFinder struct { wClient tinkworkflow.WorkflowServiceClient } -// NewFinder returns a *Finder that satisfies client.Finder. +// NewWorkflowFinder returns a *WorkflowFinder that satisfies client.WorkflowFinder. // // TODO: micahhausler: Explicitly pass in tink endpoint func NewWorkflowFinder() (*WorkflowFinder, error) { @@ -109,7 +101,7 @@ func NewWorkflowFinder() (*WorkflowFinder, error) { }, nil } -// HasActiveWorkflow finds if an active workflow exists for a particular hardware id. +// HasActiveWorkflow finds if an active workflow exists for a particular hardware ID. func (f *WorkflowFinder) HasActiveWorkflow(ctx context.Context, hwID client.HardwareID) (bool, error) { if hwID == "" { return false, errors.New("missing hardware id") diff --git a/cmd/boots/dhcp.go b/cmd/boots/dhcp.go index 858c2dc7..8502d8d6 100644 --- a/cmd/boots/dhcp.go +++ b/cmd/boots/dhcp.go @@ -83,7 +83,7 @@ func (d dhcpHandler) serveDHCP(w dhcp4.ReplyWriter, req *dhcp4.Packet) { circuitID, err := getCircuitID(req) if err != nil { - mainlog.With("mac", mac, "err", err).Info("error parsing option82") + mainlog.With("mac", mac).Error(err, "error parsing option82") } else { mainlog.With("mac", mac, "circuitID", circuitID).Info("parsed option82/circuitid") } @@ -98,7 +98,7 @@ func (d dhcpHandler) serveDHCP(w dhcp4.ReplyWriter, req *dhcp4.Packet) { ctx, j, err := d.jobmanager.CreateFromDHCP(ctx, mac, gi, circuitID) if err != nil { - mainlog.With("type", req.GetMessageType(), "mac", mac, "err", err).Info("retrieved job is empty") + mainlog.With("type", req.GetMessageType(), "mac", mac).Error(err, "retrieved job is empty") metrics.JobsInProgress.With(labels).Dec() timer.ObserveDuration() span.SetStatus(codes.Error, err.Error()) diff --git a/cmd/boots/http.go b/cmd/boots/http.go index f6254dad..4985161c 100644 --- a/cmd/boots/http.go +++ b/cmd/boots/http.go @@ -148,7 +148,7 @@ func (h *jobHandler) serveJobFile(w http.ResponseWriter, req *http.Request) { ctx, j, err := h.jobManager.CreateFromRemoteAddr(req.Context(), req.RemoteAddr) if err != nil { w.WriteHeader(http.StatusNotFound) - mainlog.With("client", req.RemoteAddr, "error", err).Info("no job found for client address") + mainlog.With("client", req.RemoteAddr).Error(err, "no job found for client address") return } diff --git a/cmd/boots/main.go b/cmd/boots/main.go index f96df50d..72d6f39f 100644 --- a/cmd/boots/main.go +++ b/cmd/boots/main.go @@ -24,6 +24,7 @@ import ( "github.com/pkg/errors" "github.com/tinkerbell/boots/client" "github.com/tinkerbell/boots/client/cacher" + "github.com/tinkerbell/boots/client/kubernetes" "github.com/tinkerbell/boots/client/packet" "github.com/tinkerbell/boots/client/standalone" "github.com/tinkerbell/boots/client/tinkerbell" @@ -79,6 +80,10 @@ type config struct { logLevel string // extraKernelArgs are key=value pairs to be added as kernel commandline to the kernel in iPXE for OSIE extraKernelArgs string + // kubeConfig is the path to a kubernetes config file + kubeconfig string + // kubeAPI is the Kubernetes API URL + kubeAPI string } func main() { @@ -113,11 +118,7 @@ func main() { if err != nil { mainlog.Fatal(err) } - workflowFinder, err := getWorkflowFinder() - if err != nil { - mainlog.Fatal(err) - } - finder, err := getHardwareFinder() + workflowFinder, finder, err := getFinders(l, cfg) if err != nil { mainlog.Fatal(err) } @@ -220,15 +221,52 @@ func main() { } } -// getWorkflowFinder returns a no-op workflow finder if tinkerbell is not the backend -func getWorkflowFinder() (client.WorkflowFinder, error) { - dataModelVersion := os.Getenv("DATA_MODEL_VERSION") - switch dataModelVersion { +func getFinders(l log.Logger, c *config) (client.WorkflowFinder, client.HardwareFinder, error) { + var hf client.HardwareFinder + var wf client.WorkflowFinder = &client.NoOpWorkflowFinder{} + var err error + + switch os.Getenv("DATA_MODEL_VERSION") { + case "": + hf, err = cacher.NewHardwareFinder(os.Getenv("FACILITY_CODE")) + if err != nil { + return nil, nil, err + } case "1": - return tinkerbell.NewWorkflowFinder() + hf, err = tinkerbell.NewHardwareFinder() + if err != nil { + return nil, nil, err + } + wf, err = tinkerbell.NewWorkflowFinder() + if err != nil { + return nil, nil, err + } + case "standalone": + saFile := os.Getenv("BOOTS_STANDALONE_JSON") + if saFile == "" { + return nil, nil, errors.New("BOOTS_STANDALONE_JSON env must be set") + } + hf, err = standalone.NewHardwareFinder(saFile) + if err != nil { + return nil, nil, err + } + // standalone uses Tinkerbell workflows + wf, err = tinkerbell.NewWorkflowFinder() + if err != nil { + return nil, nil, err + } + case "kubernetes": + kf, err := kubernetes.NewFinder(l, c.kubeAPI, c.kubeconfig) + if err != nil { + return nil, nil, err + } + wf = kf + hf = kf + // Start the client-side cache + go kf.Start(context.Background()) } - return &tinkerbell.NoOpWorkflowFinder{}, nil + return wf, hf, nil } func getReporter(l log.Logger) (client.Reporter, error) { @@ -251,25 +289,6 @@ func getReporter(l log.Logger) (client.Reporter, error) { } } -func getHardwareFinder() (client.HardwareFinder, error) { - dataModelVersion := os.Getenv("DATA_MODEL_VERSION") - switch dataModelVersion { - case "": - return cacher.NewHardwareFinder(os.Getenv("FACILITY_CODE")) - case "1": - return tinkerbell.NewHardwareFinder() - case "standalone": - saFile := os.Getenv("BOOTS_STANDALONE_JSON") - if saFile == "" { - return nil, errors.New("BOOTS_STANDALONE_JSON env must be set") - } - - return standalone.NewHardwareFinder(saFile) - } - - return nil, errors.Errorf("invalid DATA_MODEL_VERSION: %q", dataModelVersion) -} - // defaultLogger is zap logr implementation. func defaultLogger(level string) logr.Logger { config := zap.NewProductionConfig() @@ -351,6 +370,8 @@ func newCLI(cfg *config, fs *flag.FlagSet) *ffcli.Command { fs.StringVar(&cfg.dhcpAddr, "dhcp-addr", conf.BOOTPBind, "IP and port to listen on for DHCP.") fs.StringVar(&cfg.syslogAddr, "syslog-addr", conf.SyslogBind, "IP and port to listen on for syslog messages.") fs.StringVar(&cfg.extraKernelArgs, "extra-kernel-args", "", "Extra set of kernel args (k=v k=v) that are appended to the kernel cmdline when booting via iPXE.") + fs.StringVar(&cfg.kubeconfig, "kubeconfig", "", "The Kubernetes config file location. Only applies if DATA_MODEL_VERSION=kubernetes.") + fs.StringVar(&cfg.kubeAPI, "kubernetes", "", "The Kubernetes API URL, used for in-cluster client construction. Only applies if DATA_MODEL_VERSION=kubernetes.") return &ffcli.Command{ Name: name, diff --git a/cmd/boots/main_test.go b/cmd/boots/main_test.go index a0262007..30304218 100644 --- a/cmd/boots/main_test.go +++ b/cmd/boots/main_test.go @@ -78,6 +78,8 @@ FLAGS -ipxe-remote-tftp-addr remote IP where iPXE binaries are served via TFTP. Overrides -tftp-addr. -ipxe-tftp-addr local IP and port to listen on for serving iPXE binaries via TFTP (port must be 69). (default "0.0.0.0:69") -ipxe-tftp-timeout local iPXE TFTP server requests timeout. (default "5s") + -kubeconfig The Kubernetes config file location. Only applies if DATA_MODEL_VERSION=kubernetes. + -kubernetes The Kubernetes API URL, used for in-cluster client construction. Only applies if DATA_MODEL_VERSION=kubernetes. -log-level log level. (default "info") -syslog-addr IP and port to listen on for syslog messages. (default "%[1]v:514") `, defaultIP) diff --git a/go.mod b/go.mod index 8de9a211..5ee782af 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,10 @@ require ( google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect google.golang.org/grpc v1.44.0 inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 + k8s.io/apimachinery v0.23.0 + k8s.io/client-go v0.23.0 + knative.dev/pkg v0.0.0-20211119170723-a99300deff34 // indirect + sigs.k8s.io/controller-runtime v0.11.1 ) require ( @@ -50,6 +54,7 @@ require ( github.com/ashanbrown/makezero v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.0 // indirect + github.com/blendle/zapdriver v1.3.1 // indirect github.com/blizzy78/varnamelen v0.6.1 // indirect github.com/bombsimon/wsl/v3 v3.3.0 // indirect github.com/breml/bidichk v0.2.2 // indirect @@ -61,8 +66,10 @@ require ( github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect github.com/daixiang0/gci v0.3.3 // indirect github.com/denis-tingaikin/go-header v0.4.3 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect github.com/esimonov/ifshort v1.0.4 // indirect github.com/ettle/strcase v0.1.1 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fatih/color v1.13.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect @@ -85,6 +92,8 @@ require ( github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect @@ -95,6 +104,8 @@ require ( github.com/golangci/misspell v0.3.5 // indirect github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect @@ -111,6 +122,7 @@ require ( github.com/jgautheron/goconst v1.5.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/julz/importas v0.1.0 // indirect github.com/kisielk/errcheck v1.6.0 // indirect github.com/kisielk/gotool v1.0.0 // indirect @@ -132,12 +144,15 @@ require ( github.com/mgechev/revive v1.1.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/moricho/tparallel v0.2.1 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect github.com/nishanths/exhaustive v0.7.11 // indirect github.com/nishanths/predeclared v0.2.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect github.com/pin/tftp v0.0.0-20210809155059-0161c5dd2e96 // indirect @@ -198,18 +213,33 @@ require ( go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect + golang.org/x/term v0.0.0-20210916214954-140adaaadfaf // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect honnef.co/go/tools v0.2.2 // indirect + k8s.io/api v0.23.0 // indirect + k8s.io/apiextensions-apiserver v0.23.0 // indirect + k8s.io/component-base v0.23.0 // indirect + k8s.io/klog/v2 v2.30.0 // indirect + k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect + k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect mvdan.cc/gofumpt v0.3.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 // indirect + sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.0 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace github.com/sebest/xff v0.0.0-20160910043805-6c115e0ffa35 => github.com/packethost/xff v0.0.0-20190305172552-d3e9190c41b3 diff --git a/go.sum b/go.sum index 61bb8964..dadbc73f 100644 --- a/go.sum +++ b/go.sum @@ -233,6 +233,7 @@ github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAw github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/blizzy78/varnamelen v0.6.1 h1:kttPCLzXFa+0nt++Cw9fb7GrSSM4KkyIAoX/vXsbuqA= github.com/blizzy78/varnamelen v0.6.1/go.mod h1:zy2Eic4qWqjrxa60jG34cfL0VXcSwzUrIx68eJPb4Q8= @@ -423,6 +424,7 @@ github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyG github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -467,6 +469,7 @@ github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -641,6 +644,7 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -734,6 +738,7 @@ github.com/google/go-replayers/grpcreplay v1.0.0/go.mod h1:8Ig2Idjpr6gifRd6pNVgg github.com/google/go-replayers/httpreplay v0.1.2/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/mako v0.0.0-20190821191249-122f8dcef9e3/go.mod h1:YzLcVlL+NqWnmUEPuhS1LxDDwGO9WNbVlEXaF4IH35g= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -776,6 +781,7 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= @@ -945,6 +951,7 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -1144,9 +1151,11 @@ github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXy github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4= @@ -1186,6 +1195,7 @@ github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt github.com/nishanths/predeclared v0.2.1 h1:1TXtjmy4f3YCFjTxRd8zcFHOmoUir+gp0ESzjFzG2sw= github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -1208,6 +1218,7 @@ github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= @@ -1220,6 +1231,7 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= @@ -1228,6 +1240,7 @@ github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -1918,6 +1931,7 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211028175245-ba495a64dcb5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2056,6 +2070,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2084,6 +2099,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2210,6 +2226,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -2421,6 +2438,7 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -2432,6 +2450,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -2469,22 +2488,43 @@ inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 h1:acCzuUSQ79tGsM/O50VRFySfMm inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6/go.mod h1:y3MGhcFMlh0KZPMuXXow8mpjxxAk3yoDNsp4cQz54i8= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.21.4/go.mod h1:fTVGP+M4D8+00FN2cMnJqk/eb/GH53bvmNs2SVTmpFk= +k8s.io/api v0.23.0 h1:WrL1gb73VSC8obi8cuYETJGXEoFNEh3LU0Pt+Sokgro= +k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= k8s.io/apiextensions-apiserver v0.21.4/go.mod h1:OoC8LhI9LnV+wKjZkXIBbLUwtnOGJiTRE33qctH5CIk= +k8s.io/apiextensions-apiserver v0.21.4/go.mod h1:OoC8LhI9LnV+wKjZkXIBbLUwtnOGJiTRE33qctH5CIk= +k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY= +k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4= k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.21.4/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= k8s.io/apimachinery v0.21.4/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= +k8s.io/apimachinery v0.23.0 h1:mIfWRMjBuMdolAWJ3Fd+aPTMv3X9z+waiARMpvvb0HQ= k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc= +k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.21.4/go.mod h1:SErUuFBBPZUcD2nsUU8hItxoYheqyYr2o/pCINEPW8g= +k8s.io/apiserver v0.21.4/go.mod h1:SErUuFBBPZUcD2nsUU8hItxoYheqyYr2o/pCINEPW8g= +k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4= k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.21.4/go.mod h1:t0/eMKyUAq/DoQ7vW8NVVA00/nomlwC+eInsS8PxSew= k8s.io/client-go v0.21.4/go.mod h1:t0/eMKyUAq/DoQ7vW8NVVA00/nomlwC+eInsS8PxSew= +k8s.io/client-go v0.23.0 h1:vcsOqyPq7XV3QmQRCBH/t9BICJM9Q1M18qahjv+rebY= k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA= +k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA= +k8s.io/code-generator v0.21.4/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.21.4/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE= +k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.21.4/go.mod h1:ZKG0eHVX+tUDcaoIGpU3Vtk4TIjMddN9uhEWDmW6Nyg= +k8s.io/component-base v0.21.4/go.mod h1:ZKG0eHVX+tUDcaoIGpU3Vtk4TIjMddN9uhEWDmW6Nyg= +k8s.io/component-base v0.23.0 h1:UAnyzjvVZ2ZR1lF35YwtNY6VMN94WtOnArcXBu34es8= k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= @@ -2497,15 +2537,24 @@ k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +knative.dev/hack v0.0.0-20211112192837-128cf0150a69/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/hack v0.0.0-20211112192837-128cf0150a69/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/pkg v0.0.0-20211119170723-a99300deff34 h1:3PTfphK/gjxA+XJIwyDZ1g1KxRaADsI/BdhFlRAtdEE= knative.dev/pkg v0.0.0-20211119170723-a99300deff34/go.mod h1:VqUp1KWJqpTDNoiSI/heaX3uMdubImslJE2tBkP+Bbw= mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= mvdan.cc/gofumpt v0.3.0 h1:kTojdZo9AcEYbQYhGuLf/zszYthRdhDNDUi2JKTxas4= @@ -2526,14 +2575,25 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I= +sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU= +sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20220304125252-9ee63fc65a97/go.mod h1:nLkMD2WB4Jcix1qfVuJeOF4j5y/VfyeOIlTxG5Wj9co= sigs.k8s.io/controller-tools v0.8.0/go.mod h1:qE2DXhVOiEq5ijmINcFbqi9GZrrUjzB1TuJU0xa6eoY= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.0 h1:kDvPBbnPk+qYmkHmSo8vKGp438IASWofnbbUKDE/bv0= sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=