diff --git a/go.mod b/go.mod index 34f1f155d56..7bee87a93a0 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/openshift/hive/apis v0.0.0 github.com/openshift/installer v1.4.21-pre2.0.20260112230456-1c2444827f23 github.com/openshift/library-go v0.0.0-20251107090138-0de9712313a5 - github.com/openshift/machine-api-operator v0.2.1-0.20251128002018-85c00c0d525f + github.com/openshift/machine-api-operator v0.2.1-0.20251128002018-85c00c0d525f // indirect github.com/openshift/machine-api-provider-gcp v0.0.1-0.20241021180644-0eca0846914a github.com/openshift/machine-api-provider-ibmcloud v0.0.0-20231207164151-6b0b8ea7b16d github.com/pkg/errors v0.9.1 @@ -425,15 +425,12 @@ require ( google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/grpc v1.79.3 // indirect google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/gcfg.v1 v1.2.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.6.1 // indirect k8s.io/apiserver v0.34.2 // indirect - k8s.io/cloud-provider-vsphere v1.33.3 // indirect k8s.io/component-base v0.34.2 // indirect k8s.io/component-helpers v0.34.1 // indirect k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect diff --git a/go.sum b/go.sum index 51aba643b49..a954318a45b 100644 --- a/go.sum +++ b/go.sum @@ -846,8 +846,6 @@ github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235 h1:9JBeIXmnHlp github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235/go.mod h1:L49W6pfrZkfOE5iC1PqEkuLkXG4W0BX4w8b+L2Bv7fM= github.com/openshift/cloud-credential-operator v0.0.0-20240404165937-5e8812d64187 h1:v2D/+SWsOPsl4Syz1SVjo7m3L0ethuRGR++ubsb89oA= github.com/openshift/cloud-credential-operator v0.0.0-20240404165937-5e8812d64187/go.mod h1:eyA6FG71366St6Q1TW+jXdQbald0rUwtEPhAREMlyhA= -github.com/openshift/cloud-provider-vsphere v1.19.1-0.20240626105621-6464d0bb4928 h1:gX0HAKR0f40xmMWlUSn8DBMCjip8Iuzg5XToWAv6Uzw= -github.com/openshift/cloud-provider-vsphere v1.19.1-0.20240626105621-6464d0bb4928/go.mod h1:eVEtCena8tmeeYDKwZlA2w+xBKzBHbQZ4CNHV8KL4ho= github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250910145856-21d03d30056d h1:+sqUThLi/lmgT5/scmmjnS6+RZFtbdxRAscNfCPyLPI= github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250910145856-21d03d30056d/go.mod h1:9+FWWWLkVrnBo1eYhA/0Ehlq5JMgIAHtcB0IF+qV1AA= github.com/openshift/cluster-autoscaler-operator v0.0.1-0.20250219201631-227f7537c3b4 h1:Xepsi7/s1kHkemmhyWDFV21dijgXZUcT0+8YWh6CbxU= @@ -1371,8 +1369,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -1383,8 +1379,6 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 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 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/controller/machinepool/machinepool_controller.go b/pkg/controller/machinepool/machinepool_controller.go index eeae6207a21..c595cb42820 100644 --- a/pkg/controller/machinepool/machinepool_controller.go +++ b/pkg/controller/machinepool/machinepool_controller.go @@ -1393,7 +1393,7 @@ func (r *ReconcileMachinePool) createActuator( case cd.Spec.Platform.OpenStack != nil: return NewOpenStackActuator(masterMachine, r.Client, logger) case cd.Spec.Platform.VSphere != nil: - return NewVSphereActuator(masterMachine, r.scheme, logger) + return NewVSphereActuator(masterMachine, logger) default: return nil, errors.New("unsupported platform") } diff --git a/pkg/controller/machinepool/vsphereactuator.go b/pkg/controller/machinepool/vsphereactuator.go index 7a7866c5c57..7a16e8d60c7 100644 --- a/pkg/controller/machinepool/vsphereactuator.go +++ b/pkg/controller/machinepool/vsphereactuator.go @@ -1,6 +1,7 @@ package machinepool import ( + "encoding/json" "fmt" "strings" @@ -13,7 +14,6 @@ import ( installvsphere "github.com/openshift/installer/pkg/asset/machines/vsphere" installertypes "github.com/openshift/installer/pkg/types" installertypesvsphere "github.com/openshift/installer/pkg/types/vsphere" - vsphereutil "github.com/openshift/machine-api-operator/pkg/controller/vsphere" hivev1 "github.com/openshift/hive/apis/hive/v1" ) @@ -28,8 +28,8 @@ type VSphereActuator struct { var _ Actuator = &VSphereActuator{} // NewVSphereActuator is the constructor for building a VSphereActuator -func NewVSphereActuator(masterMachine *machineapi.Machine, scheme *runtime.Scheme, logger log.FieldLogger) (*VSphereActuator, error) { - osImage, err := getVSphereOSImage(masterMachine, scheme, logger) +func NewVSphereActuator(masterMachine *machineapi.Machine, logger log.FieldLogger) (*VSphereActuator, error) { + osImage, err := getVSphereOSImage(masterMachine, logger) if err != nil { logger.WithError(err).Error("error getting os image from master machine") return nil, err @@ -116,8 +116,9 @@ func (a *VSphereActuator) GenerateMachineSets(cd *hivev1.ClusterDeployment, pool } // Get the OS image from an existing master machine. -func getVSphereOSImage(masterMachine *machineapi.Machine, scheme *runtime.Scheme, logger log.FieldLogger) (string, error) { - providerSpec, err := vsphereutil.ProviderSpecFromRawExtension(masterMachine.Spec.ProviderSpec.Value) +func getVSphereOSImage(masterMachine *machineapi.Machine, logger log.FieldLogger) (string, error) { + providerSpec, err := providerSpecFromRawExtension(masterMachine.Spec.ProviderSpec.Value) + logger.Debugf("Got provider spec from raw extension: %+v", providerSpec) if err != nil { logger.WithError(err).Warn("cannot decode VSphereMachineProviderSpec from master machine") return "", errors.Wrap(err, "cannot decode VSphereMachineProviderSpec from master machine") @@ -152,3 +153,19 @@ func setFolderPath(folder, datacenter string, logger log.FieldLogger) string { } return folder } + +// ProviderSpecFromRawExtension unmarshals the JSON-encoded spec +// Inlined from https://github.com/openshift/machine-api-operator/blob/85c00c0d525fe75683afced6cfed878b3414bc7a/pkg/controller/vsphere/util.go#L202-L215 +// (last changed: 5 years ago) +func providerSpecFromRawExtension(rawExtension *runtime.RawExtension) (*machineapi.VSphereMachineProviderSpec, error) { + if rawExtension == nil { + return &machineapi.VSphereMachineProviderSpec{}, nil + } + + spec := new(machineapi.VSphereMachineProviderSpec) + if err := json.Unmarshal(rawExtension.Raw, &spec); err != nil { + return nil, fmt.Errorf("error unmarshalling providerSpec: %v", err) + } + + return spec, nil +} diff --git a/pkg/controller/machinepool/vsphereactuator_test.go b/pkg/controller/machinepool/vsphereactuator_test.go index 8828fb8efb0..a32fc4db445 100644 --- a/pkg/controller/machinepool/vsphereactuator_test.go +++ b/pkg/controller/machinepool/vsphereactuator_test.go @@ -1,22 +1,22 @@ package machinepool import ( + "encoding/json" "fmt" "testing" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/runtime" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" machineapi "github.com/openshift/api/machine/v1beta1" - vsphereutil "github.com/openshift/machine-api-operator/pkg/controller/vsphere" hivev1 "github.com/openshift/hive/apis/hive/v1" hivev1vsphere "github.com/openshift/hive/apis/hive/v1/vsphere" - "github.com/openshift/hive/pkg/util/scheme" ) func TestVSphereActuator(t *testing.T) { @@ -41,9 +41,7 @@ func TestVSphereActuator(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - scheme := scheme.GetScheme() - - actuator, err := NewVSphereActuator(test.masterMachine, scheme, log.WithField("actuator", "vsphereactuator_test")) + actuator, err := NewVSphereActuator(test.masterMachine, log.WithField("actuator", "vsphereactuator_test")) assert.NoError(t, err, "unexpected error creating VSphereActuator") generatedMachineSets, _, err := actuator.GenerateMachineSets(test.clusterDeployment, test.pool, actuator.logger) @@ -113,7 +111,7 @@ func testVSphereClusterDeployment() *hivev1.ClusterDeployment { } func testVSphereMachineSpec(machineType string) machineapi.MachineSpec { - rawVSphereProviderSpec, err := vsphereutil.RawExtensionFromProviderSpec(testVSphereProviderSpec()) + rawVSphereProviderSpec, err := rawExtensionFromProviderSpec(testVSphereProviderSpec()) if err != nil { log.WithError(err).Fatal("error encoding VSphere machine provider spec") } @@ -161,3 +159,22 @@ func testVSphereProviderSpec() *machineapi.VSphereMachineProviderSpec { DiskGiB: 120, } } + +// rawExtensionFromProviderSpec marshals the machine provider spec. +// Inlined https://github.com/openshift/machine-api-operator/blob/85c00c0d525fe75683afced6cfed878b3414bc7a/pkg/controller/vsphere/util.go#L168-L183 +// (last changed: 5 years ago) +func rawExtensionFromProviderSpec(spec *machineapi.VSphereMachineProviderSpec) (*runtime.RawExtension, error) { + if spec == nil { + return &runtime.RawExtension{}, nil + } + + var rawBytes []byte + var err error + if rawBytes, err = json.Marshal(spec); err != nil { + return nil, fmt.Errorf("error marshalling providerSpec: %v", err) + } + + return &runtime.RawExtension{ + Raw: rawBytes, + }, nil +} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/actuator.go b/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/actuator.go deleted file mode 100644 index 56def7a6feb..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/actuator.go +++ /dev/null @@ -1,202 +0,0 @@ -package vsphere - -// This is a thin layer to implement the machine actuator interface with cloud provider details. -// The lifetime of scope and reconciler is a machine actuator operation. -import ( - "context" - "fmt" - "time" - - "k8s.io/component-base/featuregate" - - machinev1 "github.com/openshift/api/machine/v1beta1" - machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" - corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/tools/record" - "k8s.io/klog/v2" - runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - scopeFailFmt = "%s: failed to create scope for machine: %v" - reconcilerFailFmt = "%s: reconciler failed to %s machine: %w" - createEventAction = "Create" - updateEventAction = "Update" - deleteEventAction = "Delete" - noEventAction = "" - requeueAfterSeconds = 20 -) - -// Actuator is responsible for performing machine reconciliation. -type Actuator struct { - client runtimeclient.Client - apiReader runtimeclient.Reader - eventRecorder record.EventRecorder - TaskIDCache map[string]string - FeatureGates featuregate.MutableFeatureGate - openshiftConfigNamespace string -} - -// ActuatorParams holds parameter information for Actuator. -type ActuatorParams struct { - Client runtimeclient.Client - APIReader runtimeclient.Reader - EventRecorder record.EventRecorder - TaskIDCache map[string]string - FeatureGates featuregate.MutableFeatureGate - OpenshiftConfigNamespace string -} - -// NewActuator returns an actuator. -func NewActuator(params ActuatorParams) *Actuator { - return &Actuator{ - client: params.Client, - apiReader: params.APIReader, - eventRecorder: params.EventRecorder, - TaskIDCache: params.TaskIDCache, - FeatureGates: params.FeatureGates, - openshiftConfigNamespace: params.OpenshiftConfigNamespace, - } -} - -// Set corresponding event based on error. It also returns the original error -// for convenience, so callers can do "return handleMachineError(...)". -func (a *Actuator) handleMachineError(machine *machinev1.Machine, err error, eventAction string) error { - klog.Errorf("%q error: %v", machine.GetName(), err) - if eventAction != noEventAction { - a.eventRecorder.Eventf(machine, corev1.EventTypeWarning, "Failed"+eventAction, "%v", err) - } - return err -} - -// Create creates a machine and is invoked by the machine controller. -func (a *Actuator) Create(ctx context.Context, machine *machinev1.Machine) error { - klog.Infof("%s: actuator creating machine", machine.GetName()) - - scope, err := newMachineScope(machineScopeParams{ - Context: ctx, - client: a.client, - machine: machine, - apiReader: a.apiReader, - featureGates: a.FeatureGates, - openshiftConfigNameSpace: a.openshiftConfigNamespace, - }) - if err != nil { - fmtErr := fmt.Errorf(scopeFailFmt, machine.GetName(), err) - return a.handleMachineError(machine, fmtErr, createEventAction) - } - - // Ensure we're not reconciling a stale machine by checking our task-id. - // This is a workaround for a cache race condition. - if val, ok := a.TaskIDCache[machine.Name]; ok { - if val != scope.providerStatus.TaskRef { - klog.Errorf("%s: machine object missing expected provider task ID, requeue", machine.GetName()) - return &machinecontroller.RequeueAfterError{RequeueAfter: requeueAfterSeconds * time.Second} - } - } - - var retErr error - err = newReconciler(scope).create() - // save the taskRef in our cache in case of any error with patch. - if scope.providerStatus.TaskRef != "" { - a.TaskIDCache[machine.Name] = scope.providerStatus.TaskRef - } - if err != nil { - fmtErr := fmt.Errorf(reconcilerFailFmt, machine.GetName(), createEventAction, err) - retErr = a.handleMachineError(machine, fmtErr, createEventAction) - } else { - a.eventRecorder.Eventf(machine, corev1.EventTypeNormal, createEventAction, "Created Machine %v", machine.GetName()) - } - - if err := scope.PatchMachine(); err != nil { - return err - } - - return retErr -} - -func (a *Actuator) Exists(ctx context.Context, machine *machinev1.Machine) (bool, error) { - klog.Infof("%s: actuator checking if machine exists", machine.GetName()) - scope, err := newMachineScope(machineScopeParams{ - Context: ctx, - client: a.client, - machine: machine, - apiReader: a.apiReader, - featureGates: a.FeatureGates, - openshiftConfigNameSpace: a.openshiftConfigNamespace, - }) - if err != nil { - return false, fmt.Errorf(scopeFailFmt, machine.GetName(), err) - } - return newReconciler(scope).exists() -} - -func (a *Actuator) Update(ctx context.Context, machine *machinev1.Machine) error { - klog.Infof("%s: actuator updating machine", machine.GetName()) - // Cleanup TaskIDCache so we don't continually grow - delete(a.TaskIDCache, machine.Name) - - scope, err := newMachineScope(machineScopeParams{ - Context: ctx, - client: a.client, - machine: machine, - apiReader: a.apiReader, - featureGates: a.FeatureGates, - openshiftConfigNameSpace: a.openshiftConfigNamespace, - }) - if err != nil { - fmtErr := fmt.Errorf(scopeFailFmt, machine.GetName(), err) - return a.handleMachineError(machine, fmtErr, updateEventAction) - } - if err := newReconciler(scope).update(); err != nil { - // Update machine and machine status in case it was modified - if err := scope.PatchMachine(); err != nil { - return err - } - fmtErr := fmt.Errorf(reconcilerFailFmt, machine.GetName(), updateEventAction, err) - return a.handleMachineError(machine, fmtErr, updateEventAction) - } - previousResourceVersion := scope.machine.ResourceVersion - - if err := scope.PatchMachine(); err != nil { - return err - } - - currentResourceVersion := scope.machine.ResourceVersion - - // Create event only if machine object was modified - if previousResourceVersion != currentResourceVersion { - a.eventRecorder.Eventf(machine, corev1.EventTypeNormal, updateEventAction, "Updated Machine %v", machine.GetName()) - } - - return nil -} - -func (a *Actuator) Delete(ctx context.Context, machine *machinev1.Machine) error { - klog.Infof("%s: actuator deleting machine", machine.GetName()) - // Cleanup TaskIDCache so we don't continually grow - // Cleanup here as well in case Update() was never successfully called. - delete(a.TaskIDCache, machine.Name) - - scope, err := newMachineScope(machineScopeParams{ - Context: ctx, - client: a.client, - machine: machine, - apiReader: a.apiReader, - featureGates: a.FeatureGates, - openshiftConfigNameSpace: a.openshiftConfigNamespace, - }) - if err != nil { - fmtErr := fmt.Errorf(scopeFailFmt, machine.GetName(), err) - return a.handleMachineError(machine, fmtErr, deleteEventAction) - } - if err := newReconciler(scope).delete(); err != nil { - if err := scope.PatchMachine(); err != nil { - return err - } - fmtErr := fmt.Errorf(reconcilerFailFmt, machine.GetName(), deleteEventAction, err) - return a.handleMachineError(machine, fmtErr, deleteEventAction) - } - a.eventRecorder.Eventf(machine, corev1.EventTypeNormal, deleteEventAction, "Deleted machine %v", machine.GetName()) - return scope.PatchMachine() -} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/machine_scope.go b/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/machine_scope.go deleted file mode 100644 index 141a19fa20a..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/machine_scope.go +++ /dev/null @@ -1,304 +0,0 @@ -package vsphere - -import ( - "context" - "errors" - "fmt" - - "k8s.io/component-base/featuregate" - - machinev1 "github.com/openshift/api/machine/v1beta1" - machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" - "github.com/openshift/machine-api-operator/pkg/controller/vsphere/session" - apicorev1 "k8s.io/api/core/v1" - apimachineryerrors "k8s.io/apimachinery/pkg/api/errors" - apimachineryutilerrors "k8s.io/apimachinery/pkg/util/errors" - vsphere "k8s.io/cloud-provider-vsphere/pkg/common/config" - "k8s.io/klog/v2" - runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - userDataSecretKey = "userData" -) - -// machineScopeParams defines the input parameters used to create a new MachineScope. -type machineScopeParams struct { - context.Context - client runtimeclient.Client - apiReader runtimeclient.Reader - machine *machinev1.Machine - featureGates featuregate.MutableFeatureGate - openshiftConfigNameSpace string -} - -// machineScope defines a scope defined around a machine and its cluster. -type machineScope struct { - context.Context - // vsphere session - session *session.Session - // api server controller runtime client - client runtimeclient.Client - // client reader that bypasses the manager's cache - apiReader runtimeclient.Reader - // vSphere cloud-provider config - vSphereConfig *vsphere.Config - // machine resource - machine *machinev1.Machine - providerSpec *machinev1.VSphereMachineProviderSpec - providerStatus *machinev1.VSphereMachineProviderStatus - machineToBePatched runtimeclient.Patch - featureGates featuregate.MutableFeatureGate -} - -// newMachineScope creates a new machineScope from the supplied parameters. -// This is meant to be called for each machine actuator operation. -func newMachineScope(params machineScopeParams) (*machineScope, error) { - if params.Context == nil { - return nil, fmt.Errorf("%v: machine scope require a context", params.machine.GetName()) - } - - vSphereConfig, err := getVSphereConfig(params.apiReader, params.openshiftConfigNameSpace) - if err != nil { - klog.Errorf("Failed to fetch vSphere config: %v", err) - } - - providerSpec, err := ProviderSpecFromRawExtension(params.machine.Spec.ProviderSpec.Value) - if err != nil { - return nil, machinecontroller.InvalidMachineConfiguration("failed to get machine config: %v", err) - } - - providerStatus, err := ProviderStatusFromRawExtension(params.machine.Status.ProviderStatus) - if err != nil { - return nil, machinecontroller.InvalidMachineConfiguration("failed to get machine provider status: %v", err.Error()) - } - - user, password, err := getCredentialsSecret(params.client, params.machine.GetNamespace(), *providerSpec) - if err != nil { - return nil, fmt.Errorf("%v: error getting credentials: %w", params.machine.GetName(), err) - } - if providerSpec.Workspace == nil { - return nil, fmt.Errorf("%v: no workspace provided", params.machine.GetName()) - } - - server := fmt.Sprintf("%s:%s", providerSpec.Workspace.Server, getVCenterPortFromConfig(vSphereConfig, providerSpec.Workspace.Server)) - authSession, err := session.GetOrCreate(params.Context, - server, providerSpec.Workspace.Datacenter, - user, password, getVCenterInsecureFlagFromConfig(vSphereConfig, providerSpec.Workspace.Server)) - if err != nil { - return nil, fmt.Errorf("failed to create vSphere session: %w", err) - } - - return &machineScope{ - Context: params.Context, - client: params.client, - apiReader: params.apiReader, - session: authSession, - machine: params.machine, - providerSpec: providerSpec, - providerStatus: providerStatus, - vSphereConfig: vSphereConfig, - featureGates: params.featureGates, - machineToBePatched: runtimeclient.MergeFrom(params.machine.DeepCopy()), - }, nil -} - -// Patch patches the machine spec and machine status after reconciling. -func (s *machineScope) PatchMachine() error { - klog.V(3).Infof("%v: patching machine", s.machine.GetName()) - - providerStatus, err := RawExtensionFromProviderStatus(s.providerStatus) - if err != nil { - return machinecontroller.InvalidMachineConfiguration("failed to get machine provider status: %v", err.Error()) - } - s.machine.Status.ProviderStatus = providerStatus - - statusCopy := *s.machine.Status.DeepCopy() - - // patch machine - if err := s.client.Patch(context.Background(), s.machine, s.machineToBePatched); err != nil { - klog.Errorf("Failed to patch machine %q: %v", s.machine.GetName(), err) - return err - } - - s.machine.Status = statusCopy - - // patch status - if err := s.client.Status().Patch(context.Background(), s.machine, s.machineToBePatched); err != nil { - klog.Errorf("Failed to patch machine status %q: %v", s.machine.GetName(), err) - return err - } - - return nil -} - -func (s *machineScope) GetSession() *session.Session { - return s.session -} - -func (s *machineScope) isNodeLinked() bool { - return s.machine.Status.NodeRef != nil && s.machine.Status.NodeRef.Name != "" -} - -func (s *machineScope) getNode() (*apicorev1.Node, error) { - var node apicorev1.Node - if !s.isNodeLinked() { - return nil, fmt.Errorf("NodeRef empty, unable to get related Node") - } - nodeName := s.machine.Status.NodeRef.Name - objectKey := runtimeclient.ObjectKey{ - Name: nodeName, - } - if err := s.apiReader.Get(s.Context, objectKey, &node); err != nil { - if apimachineryerrors.IsNotFound(err) { - klog.V(2).Infof("Node %q not found", nodeName) - return nil, err - } - klog.Errorf("Failed to get node %q: %v", nodeName, err) - return nil, err - } - - return &node, nil -} - -func (s *machineScope) checkNodeReachable() (bool, error) { - node, err := s.getNode() - if err != nil { - // do not return error if node object not found, treat it as unreachable - if apimachineryerrors.IsNotFound(err) { - return false, nil - } - return false, err - } - return nodeReachable(node), nil -} - -// deleteUnevictedPods checks respective node for reachability, -// if the node is not reachable it tries to remove pods in the 'Terminating' state. -// Returns the number of deleted pods and errors if there were any. -// Returns error, if the node is operational. -func (s *machineScope) deleteUnevictedPods() (int, error) { - node, err := s.getNode() - if err != nil { - // do not return error if node object not found, treat it as unreachable - if apimachineryerrors.IsNotFound(err) { - return 0, nil - } - return 0, err - } - if nodeReachable(node) { - return 0, fmt.Errorf("node is in operational state, won't proceed with pods deletion") - } - - terminatingPods, err := getPodList(s.Context, s.apiReader, node, []podPredicate{isTerminating}) - if err != nil { - return 0, err - } - - gracePeriodSeconds := int64(0) - deleteOptions := &runtimeclient.DeleteOptions{ - GracePeriodSeconds: &gracePeriodSeconds, - } - deletedPods := 0 - var deleteErrList []error - for _, pod := range terminatingPods.Items { - err := s.client.Delete(s.Context, &pod, deleteOptions) - if err != nil { - deleteErrList = append(deleteErrList, err) - } else { - deletedPods += 1 - } - } - if len(deleteErrList) > 0 { - return deletedPods, apimachineryutilerrors.NewAggregate(deleteErrList) - } - return deletedPods, nil -} - -func nodeReachable(node *apicorev1.Node) bool { - for _, condition := range node.Status.Conditions { - if condition.Type == apicorev1.NodeReady && condition.Status == apicorev1.ConditionUnknown { - return false - } - } - return true -} - -// GetUserData fetches the user-data from the secret referenced in the Machine's -// provider spec, if one is set. -func (s *machineScope) GetUserData() ([]byte, error) { - if s.providerSpec == nil || s.providerSpec.UserDataSecret == nil { - return nil, machinecontroller.InvalidMachineConfiguration("user data secret is missing in provider spec") - } - - userDataSecret := &apicorev1.Secret{} - - objKey := runtimeclient.ObjectKey{ - Namespace: s.machine.Namespace, - Name: s.providerSpec.UserDataSecret.Name, - } - - if err := s.client.Get(context.Background(), objKey, userDataSecret); err != nil { - return nil, err - } - - userData, exists := userDataSecret.Data[userDataSecretKey] - if !exists { - return nil, fmt.Errorf("secret %s missing %s key", objKey, userDataSecretKey) - } - - return userData, nil -} - -// getCredentialsSecret returns the username and password from the VSphere credentials secret. -// The secret is expected to be in the format documented here: -// https://vmware.github.io/vsphere-storage-for-kubernetes/documentation/k8s-secret.html -// -// Assuming the vcenter is our dev server vcsa.vmware.devcluster.openshift.com, -// the secret would be in this format: -// -// apiVersion: v1 -// kind: Secret -// metadata: -// name: vsphere -// namespace: openshift-machine-api -// type: Opaque -// data: -// vcsa.vmware.devcluster.openshift.com.username: base64 string -// vcsa.vmware.devcluster.openshift.com.password: base64 string -func getCredentialsSecret(client runtimeclient.Client, namespace string, spec machinev1.VSphereMachineProviderSpec) (string, string, error) { - if spec.CredentialsSecret == nil { - return "", "", nil - } - - var credentialsSecret apicorev1.Secret - if err := client.Get(context.Background(), - runtimeclient.ObjectKey{Namespace: namespace, Name: spec.CredentialsSecret.Name}, - &credentialsSecret); err != nil { - - if apimachineryerrors.IsNotFound(err) { - return "", "", machinecontroller.InvalidMachineConfiguration("credentials secret %v/%v not found: %v", namespace, spec.CredentialsSecret.Name, err.Error()) - } - return "", "", fmt.Errorf("error getting credentials secret %v/%v: %v", namespace, spec.CredentialsSecret.Name, err) - } - - // TODO: add provider spec validation logic and move this check there - if spec.Workspace == nil { - return "", "", errors.New("no workspace") - } - - credentialsSecretUser := fmt.Sprintf("%s.username", spec.Workspace.Server) - credentialsSecretPassword := fmt.Sprintf("%s.password", spec.Workspace.Server) - - user, exists := credentialsSecret.Data[credentialsSecretUser] - if !exists { - return "", "", machinecontroller.InvalidMachineConfiguration("secret %v/%v does not have %q field set", namespace, spec.CredentialsSecret.Name, credentialsSecretUser) - } - - password, exists := credentialsSecret.Data[credentialsSecretPassword] - if !exists { - return "", "", machinecontroller.InvalidMachineConfiguration("secret %v/%v does not have %q field set", namespace, spec.CredentialsSecret.Name, credentialsSecretPassword) - } - - return string(user), string(password), nil -} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/reconciler.go b/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/reconciler.go deleted file mode 100644 index 74240b3b73d..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/reconciler.go +++ /dev/null @@ -1,1864 +0,0 @@ -package vsphere - -import ( - "context" - "encoding/base64" - "encoding/hex" - "errors" - "fmt" - "net" - "net/netip" - "regexp" - "slices" - "strconv" - "strings" - - "github.com/vmware/govmomi/task" - - "github.com/openshift/machine-api-operator/pkg/util/ipam" - - "github.com/google/uuid" - - "github.com/vmware/govmomi/find" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/property" - "github.com/vmware/govmomi/vim25" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apimachinerytypes "k8s.io/apimachinery/pkg/types" - apimachineryutilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/component-base/featuregate" - "k8s.io/klog/v2" - "k8s.io/utils/ptr" - - apifeatures "github.com/openshift/api/features" - machinev1 "github.com/openshift/api/machine/v1beta1" - - machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" - "github.com/openshift/machine-api-operator/pkg/controller/vsphere/session" - "github.com/openshift/machine-api-operator/pkg/metrics" -) - -const ( - fullCloneDiskMoveType = string(types.VirtualMachineRelocateDiskMoveOptionsMoveAllDiskBackingsAndConsolidate) - linkCloneDiskMoveType = string(types.VirtualMachineRelocateDiskMoveOptionsCreateNewChildDiskBacking) - ethCardType = "vmxnet3" - providerIDPrefix = "vsphere://" - regionKey = "region" - zoneKey = "zone" - minimumHWVersion = 15 - // maxUnitNumber constant is used to define the maximum number of devices that can be assigned to a virtual machine's controller. - // Not all controllers support up to 30, but the maximum is 30. - // xref: https://docs.vmware.com/en/VMware-vSphere/8.0/vsphere-vm-administration/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#:~:text=If%20you%20add%20a%20hard,values%20from%200%20to%2014. - maxUnitNumber = 30 -) - -// These are the guestinfo variables used by Ignition. -// https://access.redhat.com/documentation/en-us/openshift_container_platform/4.1/html/installing/installing-on-vsphere -const ( - GuestInfoIgnitionData = "guestinfo.ignition.config.data" - GuestInfoIgnitionEncoding = "guestinfo.ignition.config.data.encoding" - GuestInfoHostname = "guestinfo.hostname" - GuestInfoNetworkKargs = "guestinfo.afterburn.initrd.network-kargs" - StealClock = "stealclock.enable" -) - -// vSphere tasks description IDs, for determinate task types (clone, delete, etc) -const ( - cloneVmTaskDescriptionId = "VirtualMachine.clone" - destroyVmTaskDescriptionId = "VirtualMachine.destroy" - powerOffVmTaskDescriptionId = "VirtualMachine.powerOff" -) - -// Reconciler runs the logic to reconciles a machine resource towards its desired state -type Reconciler struct { - *machineScope -} - -func newReconciler(scope *machineScope) *Reconciler { - return &Reconciler{ - machineScope: scope, - } -} - -// create creates machine if it does not exists. -func (r *Reconciler) create() error { - if err := validateMachine(*r.machine); err != nil { - return fmt.Errorf("%v: failed validating machine provider spec: %w", r.machine.GetName(), err) - } - - if r.providerSpec.Workspace.VMGroup != "" && !r.featureGates.Enabled(featuregate.Feature(apifeatures.FeatureGateVSphereHostVMGroupZonal)) { - return fmt.Errorf("%v: vmGroup is only available with the VSphereHostVMGroupZonal feature gate", r.machine.GetName()) - } - - if ipam.HasStaticIPConfiguration(r.providerSpec) { - outstandingClaims, err := ipam.HasOutstandingIPAddressClaims( - r.Context, - r.client, - r.machine, - r.providerSpec.Network.Devices, - ) - if err != nil { - return err - } - condition := metav1.Condition{ - Type: string(machinev1.IPAddressClaimedCondition), - Reason: machinev1.IPAddressClaimedReason, - Message: "All IP address claims are bound", - Status: metav1.ConditionTrue, - } - - if outstandingClaims > 0 { - condition.Message = fmt.Sprintf("Waiting on %d IP address claims to be bound", outstandingClaims) - condition.Reason = machinev1.WaitingForIPAddressReason - condition.Status = metav1.ConditionFalse - klog.Infof("Waiting for IPAddressClaims associated with machine %s to be bound", r.machine.Name) - } - if err := setProviderStatus("", condition, r.machineScope, nil); err != nil { - return fmt.Errorf("could not set provider status: %w", err) - } - } - - // We only clone the VM template if we have no taskRef. - if r.providerStatus.TaskRef == "" { - klog.V(4).Infof("%v: ProviderStatus does not have TaskRef", r.machine.GetName()) - if !r.machineScope.session.IsVC() { - return fmt.Errorf("%v: not connected to a vCenter", r.machine.GetName()) - } - - // Attempt to power on instance in situation where we alredy cloned the instance and lost taskRef. - klog.V(4).Infof("%v: InstanceState is: %q", r.machine.GetName(), ptr.Deref(r.machineScope.providerStatus.InstanceState, "")) - if types.VirtualMachinePowerState(ptr.Deref(r.machineScope.providerStatus.InstanceState, "")) == types.VirtualMachinePowerStatePoweredOff { - klog.Infof("Powering on cloned machine without taskID: %v", r.machine.Name) - - task, err := powerOn(r.machineScope) - if err != nil { - metrics.RegisterFailedInstanceCreate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "PowerOn task finished with error", - }) - - conditionFailed := conditionFailed() - conditionFailed.Message = err.Error() - statusError := setProviderStatus(task, conditionFailed, r.machineScope, nil) - if statusError != nil { - return fmt.Errorf("failed to set provider status: %w", err) - } - - return fmt.Errorf("%v: failed to power on machine: %w", r.machine.GetName(), err) - } - - return setProviderStatus(task, conditionSuccess(), r.machineScope, nil) - } - - klog.Infof("%v: cloning", r.machine.GetName()) - task, err := clone(r.machineScope) - if err != nil { - metrics.RegisterFailedInstanceCreate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "Clone task finished with error", - }) - conditionFailed := conditionFailed() - conditionFailed.Message = err.Error() - statusError := setProviderStatus(task, conditionFailed, r.machineScope, nil) - if statusError != nil { - return fmt.Errorf("failed to set provider status: %w", err) - } - return err - } - return setProviderStatus(task, conditionSuccess(), r.machineScope, nil) - } - - moTask, err := r.session.GetTask(r.Context, r.providerStatus.TaskRef) - if err != nil { - metrics.RegisterFailedInstanceCreate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "GetTask finished with error", - }) - return err - } - - if moTask == nil { - // Possible eventual consistency problem from vsphere - // TODO: change error message here to indicate this might be expected. - return fmt.Errorf("unexpected moTask nil") - } - - if taskIsFinished, err := taskIsFinished(moTask); err != nil { - if taskIsFinished { - metrics.RegisterFailedInstanceCreate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "Task finished with error", - }) - conditionFailed := conditionFailed() - conditionFailed.Message = err.Error() - statusError := setProviderStatus(moTask.Reference().Value, conditionFailed, r.machineScope, nil) - if statusError != nil { - return fmt.Errorf("failed to set provider status: %w", statusError) - } - return machinecontroller.CreateMachine("%s", err.Error()) - } else { - return fmt.Errorf("failed to check task status: %w", err) - } - } else { - if taskIsFinished { - klog.V(4).Infof("%v task %v has completed", moTask.Info.DescriptionId, moTask.Reference().Value) - } else { - return fmt.Errorf("%v task %v has not finished", moTask.Info.DescriptionId, moTask.Reference().Value) - } - } - - // if clone task finished successfully, power on the vm - // The simulator task.Info.DescriptionId is different (VirtualMachine.cloneVM) - if strings.Contains(moTask.Info.DescriptionId, cloneVmTaskDescriptionId) { - if r.machineScope.providerSpec.Workspace.VMGroup != "" { - klog.Infof("Adding on cloned machine: %s to vm group: %s", r.machine.Name, r.machineScope.providerSpec.Workspace.VMGroup) - - if err := modifyVMGroup(r.machineScope, false); err != nil { - var taskError task.Error - if errors.As(err, &taskError) { - return fmt.Errorf("could not update VM Group membership: %w", taskError) - } - - return fmt.Errorf("could not update VM Group membership: %w", err) - } - } - - klog.Infof("Powering on cloned machine: %v", r.machine.Name) - task, err := powerOn(r.machineScope) - if err != nil { - metrics.RegisterFailedInstanceCreate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "PowerOn task finished with error", - }) - conditionFailed := conditionFailed() - conditionFailed.Message = err.Error() - statusError := setProviderStatus(task, conditionFailed, r.machineScope, nil) - if statusError != nil { - return fmt.Errorf("failed to set provider status: %w", err) - } - return err - } - return setProviderStatus(task, conditionSuccess(), r.machineScope, nil) - } - - // If taskIsFinished then next reconcile should result in update. - return nil -} - -// update finds a vm and reconciles the machine resource status against it. -func (r *Reconciler) update() error { - if err := validateMachine(*r.machine); err != nil { - return fmt.Errorf("%v: failed validating machine provider spec: %w", r.machine.GetName(), err) - } - - if r.providerStatus.TaskRef != "" { - moTask, err := r.session.GetTask(r.Context, r.providerStatus.TaskRef) - if err != nil { - if !isRetrieveMONotFound(r.providerStatus.TaskRef, err) { - metrics.RegisterFailedInstanceUpdate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "GetTask finished with error", - }) - return err - } - } - if moTask != nil { - if taskIsFinished, err := taskIsFinished(moTask); err != nil { - metrics.RegisterFailedInstanceUpdate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "Task finished with error", - }) - return fmt.Errorf("%v task %v finished with error: %w", moTask.Info.DescriptionId, moTask.Reference().Value, err) - } else if !taskIsFinished { - return fmt.Errorf("%v task %v has not finished", moTask.Info.DescriptionId, moTask.Reference().Value) - } - } - } - - vmRef, err := findVM(r.machineScope) - if err != nil { - metrics.RegisterFailedInstanceUpdate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "FindVM finished with error", - }) - if !isNotFound(err) { - return err - } - return fmt.Errorf("vm not found on update: %w", err) - } - - vm := &virtualMachine{ - Context: r.machineScope.Context, - Obj: object.NewVirtualMachine(r.machineScope.session.Client.Client, vmRef), - Ref: vmRef, - } - - if err := vm.reconcileTags(r.Context, r.session, r.machine, r.providerSpec); err != nil { - metrics.RegisterFailedInstanceUpdate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "ReconcileTags finished with error", - }) - return fmt.Errorf("failed to reconcile tags: %w", err) - } - - if err := r.reconcileMachineWithCloudState(vm, r.providerStatus.TaskRef); err != nil { - metrics.RegisterFailedInstanceUpdate(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "ReconcileWithCloudState finished with error", - }) - return err - } - - return nil -} - -// exists returns true if machine exists. -func (r *Reconciler) exists() (bool, error) { - if err := validateMachine(*r.machine); err != nil { - return false, fmt.Errorf("%v: failed validating machine provider spec: %w", r.machine.GetName(), err) - } - - vmRef, err := findVM(r.machineScope) - if err != nil { - if !isNotFound(err) { - return false, err - } - klog.Infof("%v: does not exist", r.machine.GetName()) - return false, nil - } - - // Check if machine was powered on after clone. - // If it is powered off and in "Provisioning" phase, treat machine as non-existed yet and proceed with creation procedure. - powerState := types.VirtualMachinePowerState(ptr.Deref(r.machineScope.providerStatus.InstanceState, "")) - if powerState == "" || ptr.Deref(r.machine.Status.Phase, "") == machinev1.PhaseProvisioning { - vm := &virtualMachine{ - Context: r.machineScope.Context, - Obj: object.NewVirtualMachine(r.machineScope.session.Client.Client, vmRef), - Ref: vmRef, - } - powerState, err = vm.getPowerState() - if err != nil { - return false, fmt.Errorf("%v: failed checking machine's power state: %w", r.machine.GetName(), err) - } - } - - if ptr.Deref(r.machine.Status.Phase, "") == machinev1.PhaseProvisioning && powerState == types.VirtualMachinePowerStatePoweredOff { - klog.Infof("%v: already exists, but was not powered on after clone", r.machine.GetName()) - r.machineScope.providerStatus.InstanceState = ptr.To(string(powerState)) - if err := r.machineScope.PatchMachine(); err != nil { - return false, fmt.Errorf("%v: failed to patch machine: %w", r.machine.GetName(), err) - } - return false, nil - } - - klog.Infof("%v: already exists", r.machine.GetName()) - return true, nil -} - -func (r *Reconciler) delete() error { - if r.providerStatus.TaskRef != "" { - // TODO: We need to use a separate status field for the create and the - // delete taskref. - moTask, err := r.session.GetTask(r.Context, r.providerStatus.TaskRef) - if err != nil { - if !isRetrieveMONotFound(r.providerStatus.TaskRef, err) { - return err - } - } - if moTask != nil { - if taskIsFinished, err := taskIsFinished(moTask); err != nil { - // Check if latest task is not a task for vm cloning - if taskIsFinished && moTask.Info.DescriptionId != cloneVmTaskDescriptionId { - metrics.RegisterFailedInstanceDelete(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "Task finished with error", - }) - klog.Errorf("Delete task finished with error: %v", err) - return fmt.Errorf("%v task %v finished with error: %w", moTask.Info.DescriptionId, moTask.Reference().Value, err) - } else { - klog.Warningf( - "TaskRef points to clone task which finished with error: %v. Proceeding with machine deletion", err, - ) - } - } else if !taskIsFinished { - return fmt.Errorf("%v task %v has not finished", moTask.Info.DescriptionId, moTask.Reference().Value) - } - } - } - - vmRef, err := findVM(r.machineScope) - if err != nil { - if !isNotFound(err) { - metrics.RegisterFailedInstanceDelete(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "FindVM finished with error", - }) - return err - } - klog.Infof("%v: vm does not exist", r.machine.GetName()) - - // remove any finalizers for IPAddressClaims which may be associated with the machine - err = ipam.RemoveFinalizersForIPAddressClaims(r.Context, r.client, *r.machine) - if err != nil { - return fmt.Errorf("unable to remove finalizer for IP address claims: %w", err) - } - - return nil - } - - vm := &virtualMachine{ - Context: r.Context, - Obj: object.NewVirtualMachine(r.machineScope.session.Client.Client, vmRef), - Ref: vmRef, - } - - powerState, err := vm.getPowerState() - if err != nil { - return fmt.Errorf("can not determine %v vm power state: %w", r.machine.GetName(), err) - } - if powerState != types.VirtualMachinePowerStatePoweredOff { - powerOffTaskRef, err := vm.powerOffVM() - if err != nil { - return fmt.Errorf("%v: failed to power off vm: %w", r.machine.GetName(), err) - } - if err := setProviderStatus(powerOffTaskRef, conditionSuccess(), r.machineScope, vm); err != nil { - return fmt.Errorf("failed to set provider status: %w", err) - } - return fmt.Errorf("powering off vm is in progress, requeuing") - } - - // At this point node should be drained and vm powered off already. - // We need to check attached disks and ensure that all disks potentially related to PVs were detached - // to prevent possible data loss. - // Destroying a VM with attached disks might lead to data loss in case pvs are handled by the intree storage driver. - - _, drainSkipped := r.machine.ObjectMeta.Annotations[machinecontroller.ExcludeNodeDrainingAnnotation] - - // If node linked to the machine, and node was drained checking node status first - if r.machineScope.isNodeLinked() && !drainSkipped { - // After node draining, make sure volumes are detached before deleting the Node. - attached, err := r.nodeHasVolumesAttached(r.Context, r.machine.Status.NodeRef.Name, r.machine.Name) - if err != nil { - return fmt.Errorf("failed to determine if node %v has attached volumes: %w", r.machine.Status.NodeRef.Name, err) - } - if attached { - // If there are volumes still attached, it's possible that node draining did not fully finish, - // this might happen if the kubelet was non-functional during the draining procedure. - // Try forcefully deleting pods in the "Terminating" state to trigger persistent volumes detachment. - klog.Warningf( - "Attached volumes detected on a powered off node, node draining may not succeed. " + - "Attempting to delete unevicted pods", - ) - numPodsDeleted, err := r.machineScope.deleteUnevictedPods() - klog.Warningf("Deleted %d pods", numPodsDeleted) - if err != nil { - return fmt.Errorf("unable to fully drain node, can not delete unevicted pods: %w", err) - } - return fmt.Errorf("node %v has attached volumes, requeuing", r.machine.Status.NodeRef.Name) - } - } - - klog.V(3).Infof("Checking attached disks before vm destroy") - disks, err := vm.getAttachedDisks() - if err != nil { - return fmt.Errorf("%v: can not obtain virtual disks attached to the vm: %w", r.machine.GetName(), err) - } - - additionalDisks := len(r.providerSpec.DataDisks) - // Currently, MAPI only allows VMs to be configured w/ 1 primary disk in the template and a limited number of additional - // disks via the data disks configuration. So, we are expecting the VM to have only one disk, which is OS disk, plus - // the additional disks defined in the DataDisks configuration. - if len(disks) > 1+additionalDisks { - // If node drain was skipped we need to detach disks forcefully to prevent possible data corruption. - if drainSkipped { - klog.V(1).Infof( - "%s: drain was skipped for the machine, detaching disks before vm destruction to prevent data loss", - r.machine.GetName(), - ) - if err := vm.detachDisks(filterOutVmOsDisk(disks, r.machine)); err != nil { - return fmt.Errorf("failed to detach disks: %w", err) - } - klog.V(1).Infof( - "%s: disks were detached", r.machine.GetName(), - ) - return errors.New( - "disks were detached, vm will be attempted to destroy in next reconciliation, requeuing", - ) - } - - // Block vm destruction till attach-detach controller has properly detached disks - return errors.New( - "additional attached disks detected, block vm destruction and wait for disks to be detached", - ) - } - - task, err := vm.Obj.Destroy(r.Context) - if err != nil { - metrics.RegisterFailedInstanceDelete(&metrics.MachineLabels{ - Name: r.machine.Name, - Namespace: r.machine.Namespace, - Reason: "Destroy finished with error", - }) - return fmt.Errorf("%v: failed to destroy vm: %w", r.machine.GetName(), err) - } - - if r.machineScope.providerSpec.Workspace.VMGroup != "" { - klog.Infof("Removing machine: %v from vm group: %v", r.machine.Name, r.machineScope.providerSpec.Workspace.VMGroup) - if err := modifyVMGroup(r.machineScope, true); err != nil { - return fmt.Errorf("failed to remove machine from vm group: %w", err) - } - } - - if err := setProviderStatus(task.Reference().Value, conditionSuccess(), r.machineScope, vm); err != nil { - return fmt.Errorf("failed to set provider status: %w", err) - } - - // TODO: consider returning an error to specify retry time here - return fmt.Errorf("destroying vm in progress, requeuing") -} - -// nodeHasVolumesAttached returns true if node status still have volumes attached -// pod deletion and volume detach happen asynchronously, so pod could be deleted before volume detached from the node -// this could cause issue for some storage provisioner, for example, vsphere-volume this is problematic -// because if the node is deleted before detach success, then the underline VMDK will be deleted together with the Machine -// so after node draining we need to check if all volumes are detached before deleting the node. -func (r *Reconciler) nodeHasVolumesAttached(ctx context.Context, nodeName string, machineName string) (bool, error) { - node := &corev1.Node{} - if err := r.apiReader.Get(ctx, apimachinerytypes.NamespacedName{Name: nodeName}, node); err != nil { - if apierrors.IsNotFound(err) { - klog.Errorf("Could not find node from noderef, it may have already been deleted: %v", err) - return false, nil - } - return true, err - } - - return len(node.Status.VolumesAttached) != 0, nil -} - -// reconcileMachineWithCloudState reconcile machineSpec and status with the latest cloud state -func (r *Reconciler) reconcileMachineWithCloudState(vm *virtualMachine, taskRef string) error { - klog.V(3).Infof("%v: reconciling machine with cloud state", r.machine.GetName()) - // TODO: reconcile task - - if err := r.reconcileRegionAndZoneLabels(vm); err != nil { - // Not treating this is as a fatal error for now. - klog.Errorf("Failed to reconcile region and zone labels: %v", err) - } - - klog.V(3).Infof("%v: reconciling providerID", r.machine.GetName()) - if err := r.reconcileProviderID(vm); err != nil { - return err - } - - klog.V(3).Infof("%v: reconciling network", r.machine.GetName()) - if err := r.reconcileNetwork(vm); err != nil { - return err - } - - klog.V(3).Infof("%v: reconciling powerstate annotation", r.machine.GetName()) - if err := r.reconcilePowerStateAnnontation(vm); err != nil { - return err - } - - return setProviderStatus(taskRef, conditionSuccess(), r.machineScope, vm) -} - -// reconcileRegionAndZoneLabels reconciles the labels on the Machine containing -// region and zone information -- provided the vSphere cloud provider has been -// configured with the labels that identify region and zone, and the configured -// tags are found somewhere in the ancestry of the given virtual machine. -func (r *Reconciler) reconcileRegionAndZoneLabels(vm *virtualMachine) error { - if r.vSphereConfig == nil { - klog.Warning("No vSphere cloud provider config. " + - "Will not set region and zone labels.") - return nil - } - - regionLabel := r.vSphereConfig.Labels.Region - zoneLabel := r.vSphereConfig.Labels.Zone - - var res map[string]string - - err := r.session.WithCachingTagsManager(vm.Context, func(c *session.CachingTagsManager) error { - var err error - res, err = vm.getRegionAndZone(c, regionLabel, zoneLabel) - - return err - }) - - if err != nil { - return err - } - - if r.machine.Labels == nil { - r.machine.Labels = make(map[string]string) - } - - r.machine.Labels[machinecontroller.MachineRegionLabelName] = res[regionKey] - r.machine.Labels[machinecontroller.MachineAZLabelName] = res[zoneKey] - - return nil -} - -func (r *Reconciler) reconcileProviderID(vm *virtualMachine) error { - providerID, err := convertUUIDToProviderID(vm.Obj.UUID(vm.Context)) - if err != nil { - return err - } - r.machine.Spec.ProviderID = &providerID - return nil -} - -// convertUUIDToProviderID transforms a UUID string into a provider ID. -func convertUUIDToProviderID(UUID string) (string, error) { - parsedUUID, err := uuid.Parse(UUID) - if err != nil { - return "", err - } - return providerIDPrefix + parsedUUID.String(), nil -} - -func (r *Reconciler) reconcileNetwork(vm *virtualMachine) error { - currentNetworkStatusList, err := vm.getNetworkStatusList(r.session.Client.Client) - if err != nil { - return fmt.Errorf("error getting network status: %v", err) - } - - //If the VM is powered on then issue requeues until all of the VM's - //networks have IP addresses. - expectNetworkLen, currentNetworkLen := len(r.providerSpec.Network.Devices), len(currentNetworkStatusList) - if expectNetworkLen != currentNetworkLen { - return fmt.Errorf("invalid network count: expected=%d current=%d", expectNetworkLen, currentNetworkLen) - } - - var ipAddrs []corev1.NodeAddress - for _, netStatus := range currentNetworkStatusList { - for _, ip := range netStatus.IPAddrs { - ipAddrs = append(ipAddrs, corev1.NodeAddress{ - Type: corev1.NodeInternalIP, - Address: ip, - }) - } - } - - // Using Name() if InventoryPath is empty will return empty name - // see: https://github.com/vmware/govmomi/blob/master/object/common.go#L66-L75 - // Using ObjectName() as it will query from VirtualMachine properties - - vmName, err := vm.Obj.ObjectName(vm.Context) - if err != nil { - return fmt.Errorf("error getting virtual machine name: %v", err) - } - - ipAddrs = append(ipAddrs, corev1.NodeAddress{ - Type: corev1.NodeInternalDNS, - Address: vmName, - }) - - klog.V(3).Infof("%v: reconciling network: IP addresses: %v", r.machine.GetName(), ipAddrs) - r.machine.Status.Addresses = ipAddrs - - // If static IP, verify machine still has IPAddressClaim w/ owner field configure - if ipam.HasStaticIPConfiguration(r.providerSpec) { - err = ipam.VerifyIPAddressOwners(r.Context, r.client, r.machine, r.providerSpec.Network.Devices) - if err != nil { - return fmt.Errorf("error verifying ip address claims: %v", err) - } - } - - return nil -} - -func (r *Reconciler) reconcilePowerStateAnnontation(vm *virtualMachine) error { - if vm == nil { - return errors.New("provided VM is nil") - } - - // This can return an error if machine is being deleted - powerState, err := vm.getPowerState() - if err != nil { - return err - } - - if r.machine.Annotations == nil { - r.machine.Annotations = map[string]string{} - } - r.machine.Annotations[machinecontroller.MachineInstanceStateAnnotationName] = string(powerState) - - return nil -} - -func validateMachine(machine machinev1.Machine) error { - if machine.Labels[machinev1.MachineClusterIDLabel] == "" { - return machinecontroller.InvalidMachineConfiguration("%v: missing %q label", machine.GetName(), machinev1.MachineClusterIDLabel) - } - - return nil -} - -func findVM(s *machineScope) (types.ManagedObjectReference, error) { - uuid := string(s.machine.UID) - - vm, err := s.GetSession().FindVM(s.Context, uuid, s.machine.Name) - if err != nil { - if isNotFound(err) { - return types.ManagedObjectReference{}, errNotFound{instanceUUID: true, uuid: uuid} - } - return types.ManagedObjectReference{}, err - } - - if vm == nil { - return types.ManagedObjectReference{}, errNotFound{instanceUUID: true, uuid: uuid} - } - - return vm.Reference(), nil -} - -// errNotFound is returned by the findVM function when a VM is not found. -type errNotFound struct { - instanceUUID bool - uuid string -} - -func (e errNotFound) Error() string { - if e.instanceUUID { - return fmt.Sprintf("vm with instance uuid %s not found", e.uuid) - } - return fmt.Sprintf("vm with bios uuid %s not found", e.uuid) -} - -func isNotFound(err error) bool { - switch err.(type) { - case errNotFound, *errNotFound, *find.NotFoundError: - return true - default: - return false - } -} - -func getSubnetMask(prefix netip.Prefix) (string, error) { - prefixLength := net.IPv4len * 8 - if prefix.Addr().Is6() { - prefixLength = net.IPv6len * 8 - } - ipMask := net.CIDRMask(prefix.Masked().Bits(), prefixLength) - maskBytes, err := hex.DecodeString(ipMask.String()) - if err != nil { - return "", fmt.Errorf("could not translate ip mask: %w", err) - } - ip := net.IP(maskBytes) - maskStr := ip.To16().String() - return maskStr, nil -} - -// getAddressesFromPool retrieves IP addresses and associated gateway from IP address pools -func getAddressesFromPool(configIdx int, networkConfig machinev1.NetworkDeviceSpec, s *machineScope) ([]string, string, error) { - addresses := []string{} - var gateway string - for poolIdx := range networkConfig.AddressesFromPools { - claimName := ipam.GetIPAddressClaimName(s.machine, configIdx, poolIdx) - ipAddress, err := ipam.RetrieveBoundIPAddress(s.Context, s.client, s.machine, claimName) - if err != nil { - return nil, "", fmt.Errorf("error retrieving bound IP address: %w", err) - } - ipAddressSpec := ipAddress.Spec - addresses = append(addresses, fmt.Sprintf("%s/%d", ipAddressSpec.Address, ipAddressSpec.Prefix)) - if len(ipAddressSpec.Gateway) > 0 { - gateway = ipAddressSpec.Gateway - } - } - return addresses, gateway, nil -} - -// constructKargsFromNetworkConfig builds a string which comprises ip and nameserver stanzas -// which are consumed by guestinfo.afterburn.initrd.network-kargs. -func constructKargsFromNetworkConfig(s *machineScope) (string, error) { - outKargs := "" - networkConfigs := s.providerSpec.Network.Devices - for configIdx, networkConfig := range networkConfigs { - // retrieve any IP addresses assigned by an IP address pool - addressesFromPool, gatewayFromPool, err := getAddressesFromPool(configIdx, networkConfig, s) - if err != nil { - return "", fmt.Errorf("error getting addresses from IP pool: %w", err) - } - var gateway string - if len(gatewayFromPool) > 0 { - gateway = gatewayFromPool - } else { - gateway = networkConfig.Gateway - } - - var gatewayIp netip.Addr - if len(gateway) > 0 { - gatewayIp, err = netip.ParseAddr(gateway) - if err != nil { - return "", fmt.Errorf("error parsing gateway address: %w", err) - } - } - - ipAddresses := []string{} - ipAddresses = append(ipAddresses, networkConfig.IPAddrs...) - ipAddresses = append(ipAddresses, addressesFromPool...) - - // construct IP address network kargs for each IP address - for _, address := range ipAddresses { - prefix, err := netip.ParsePrefix(address) - if err != nil { - return "", fmt.Errorf("error parsing prefix: %w", err) - } - var ipStr, gatewayStr, maskStr string - addr := prefix.Addr() - // IPv6 addresses must be wrapped in [] for dracut network kargs - if addr.Is6() { - maskStr = fmt.Sprintf("%d", prefix.Bits()) - ipStr = fmt.Sprintf("[%s]", addr.String()) - if len(gateway) > 0 && gatewayIp.Is6() { - gatewayStr = fmt.Sprintf("[%s]", gateway) - } - } else if addr.Is4() { - maskStr, err = getSubnetMask(prefix) - if err != nil { - return "", fmt.Errorf("error getting subnet mask: %w", err) - } - if len(gateway) > 0 && gatewayIp.Is4() { - gatewayStr = gateway - } - ipStr = addr.String() - } else { - return "", errors.New("IP address must adhere to IPv4 or IPv6 format") - } - - outKargs = outKargs + fmt.Sprintf("ip=%s::%s:%s:::none ", ipStr, gatewayStr, maskStr) - } - - // construct nameserver network karg for each defined nameserver - for _, nameserver := range networkConfig.Nameservers { - ip := net.ParseIP(nameserver) - if ip.To4() == nil { - nameserver = fmt.Sprintf("[%s]", nameserver) - } - outKargs = outKargs + fmt.Sprintf("nameserver=%s ", nameserver) - } - } - return outKargs, nil -} - -func isRetrieveMONotFound(taskRef string, err error) bool { - return err.Error() == fmt.Sprintf("ServerFaultCode: The object 'vim.Task:%v' has already been deleted or has not been completely created", taskRef) -} - -func getHwVersion(ctx context.Context, vm *object.VirtualMachine) (int, error) { - var _vm mo.VirtualMachine - if err := vm.Properties(ctx, vm.Reference(), []string{"config.version"}, &_vm); err != nil { - return 0, fmt.Errorf("error getting hw version information for vm %s: %w", vm.Name(), err) - } - - versionString := _vm.Config.Version - version := strings.TrimPrefix(versionString, "vmx-") - parsedVersion, err := strconv.Atoi(version) - if err != nil { - return 0, fmt.Errorf("can not extract hardware version from version string: %s, format unknown", versionString) - } - return parsedVersion, nil -} - -func clone(s *machineScope) (string, error) { - userData, err := s.GetUserData() - if err != nil { - return "", err - } - - vmTemplate, err := s.GetSession().FindVM(*s, "", s.providerSpec.Template) - if err != nil { - const multipleFoundMsg = "multiple templates found, specify one in config" - const notFoundMsg = "template not found, specify valid value" - defaultError := fmt.Errorf("unable to get template %q: %w", s.providerSpec.Template, err) - return "", handleVSphereError(multipleFoundMsg, notFoundMsg, defaultError, err) - } - - hwVersion, err := getHwVersion(s.Context, vmTemplate) - if err != nil { - return "", machinecontroller.InvalidMachineConfiguration( - "Unable to detect machine template HW version for machine '%s': %v", s.machine.GetName(), err, - ) - } - if hwVersion < minimumHWVersion { - return "", machinecontroller.InvalidMachineConfiguration( - "Hardware lower than %d is not supported, clone stopped. "+ - "Detected machine template version is %d. "+ - "Please update machine template: https://docs.openshift.com/container-platform/latest/updating/updating_a_cluster/updating-hardware-on-nodes-running-on-vsphere.html", - minimumHWVersion, hwVersion, - ) - } - - // Default clone type is FullClone, having snapshot on clonee template will cause incorrect disk sizing. - diskMoveType := fullCloneDiskMoveType - var snapshotRef *types.ManagedObjectReference - - // If a linked clone is requested then a MoRef for a snapshot must be - // found with which to perform the linked clone. - // Empty clone mode is a full clone, - // because otherwise disk size from provider spec will not be respected. - if s.providerSpec.CloneMode == machinev1.LinkedClone { - if s.providerSpec.DiskGiB > 0 { - klog.Warningf("LinkedClone mode is set. Disk size parameter from ProviderSpec will be ignored") - } - if s.providerSpec.Snapshot == "" { - klog.V(3).Infof("%v: no snapshot name provided, getting snapshot using template", s.machine.GetName()) - var vm mo.VirtualMachine - if err := vmTemplate.Properties(s.Context, vmTemplate.Reference(), []string{"snapshot"}, &vm); err != nil { - return "", fmt.Errorf("error getting snapshot information for template %s: %w", vmTemplate.Name(), err) - } - - if vm.Snapshot != nil { - snapshotRef = vm.Snapshot.CurrentSnapshot - } - } else { - klog.V(3).Infof("%v: searching for snapshot by name %s", s.machine.GetName(), s.providerSpec.Snapshot) - var err error - snapshotRef, err = vmTemplate.FindSnapshot(s.Context, s.providerSpec.Snapshot) - if err != nil { - // Maybe return an error there? - klog.V(3).Infof("%v: failed to find snapshot %s, fallback to FullClone", s.machine.GetName(), s.providerSpec.Snapshot) - } - } - - if snapshotRef != nil { - diskMoveType = linkCloneDiskMoveType - } - } - - var folderPath, datastorePath, resourcepoolPath string - if s.providerSpec.Workspace != nil { - folderPath = s.providerSpec.Workspace.Folder - datastorePath = s.providerSpec.Workspace.Datastore - resourcepoolPath = s.providerSpec.Workspace.ResourcePool - } - - folder, err := s.GetSession().Finder.FolderOrDefault(s, folderPath) - if err != nil { - const multipleFoundMsg = "multiple folders found, specify one in config" - const notFoundMsg = "folder not found, specify valid value" - defaultError := fmt.Errorf("unable to get folder for %q: %w", folderPath, err) - return "", handleVSphereError(multipleFoundMsg, notFoundMsg, defaultError, err) - } - - datastore, err := s.GetSession().Finder.DatastoreOrDefault(s, datastorePath) - if err != nil { - const multipleFoundMsg = "multiple datastores found, specify one in config" - const notFoundMsg = "datastore not found, specify valid value" - defaultError := fmt.Errorf("unable to get datastore for %q: %w", datastorePath, err) - return "", handleVSphereError(multipleFoundMsg, notFoundMsg, defaultError, err) - } - - resourcepool, err := s.GetSession().Finder.ResourcePoolOrDefault(s, resourcepoolPath) - if err != nil { - const multipleFoundMsg = "multiple resource pools found, specify one in config" - const notFoundMsg = "resource pool not found, specify valid value" - defaultError := fmt.Errorf("unable to get resource pool for %q: %w", resourcepool, err) - return "", handleVSphereError(multipleFoundMsg, notFoundMsg, defaultError, err) - } - - numCPUs := s.providerSpec.NumCPUs - - numCoresPerSocket := s.providerSpec.NumCoresPerSocket - if numCoresPerSocket == 0 { - numCoresPerSocket = numCPUs - } - - devices, err := vmTemplate.Device(s.Context) - if err != nil { - return "", fmt.Errorf("error getting devices %v", err) - } - - // Create a new list of device specs for cloning the VM. - deviceSpecs := []types.BaseVirtualDeviceConfigSpec{} - - // Only non-linked clones may expand the size of the template's disk. - if snapshotRef == nil { - diskSpec, err := getDiskSpec(s, devices) - if err != nil { - return "", fmt.Errorf("error getting disk spec for %q: %w", s.providerSpec.Snapshot, err) - } - deviceSpecs = append(deviceSpecs, diskSpec) - } - - // Process all DataDisks definitions to dynamically create and add disks to the VM - additionalDisks, err := createDataDisks(s, devices) - if err != nil { - return "", fmt.Errorf("error getting additional disk specs: %w", err) - } - deviceSpecs = append(deviceSpecs, additionalDisks...) - - klog.V(3).Infof("Getting network devices") - networkDevices, err := getNetworkDevices(s, resourcepool, devices) - if err != nil { - return "", fmt.Errorf("error getting network specs: %w", err) - } - - deviceSpecs = append(deviceSpecs, networkDevices...) - - extraConfig := []types.BaseOptionValue{} - - extraConfig = append(extraConfig, IgnitionConfig(userData)...) - extraConfig = append(extraConfig, &types.OptionValue{ - Key: GuestInfoHostname, - Value: s.machine.GetName(), - }) - extraConfig = append(extraConfig, &types.OptionValue{ - Key: StealClock, - Value: "TRUE", - }) - - if ipam.HasStaticIPConfiguration(s.providerSpec) { - networkKargs, err := constructKargsFromNetworkConfig(s) - if err != nil { - return "", err - } - if len(networkKargs) > 0 { - extraConfig = append(extraConfig, &types.OptionValue{ - Key: GuestInfoNetworkKargs, - Value: networkKargs, - }) - } - } - - spec := types.VirtualMachineCloneSpec{ - Config: &types.VirtualMachineConfigSpec{ - Annotation: s.machine.GetName(), - // Assign the clone's InstanceUUID the value of the Kubernetes Machine - // object's UID. This allows lookup of the cloned VM prior to knowing - // the VM's UUID. - InstanceUuid: string(s.machine.UID), - Flags: newVMFlagInfo(), - ExtraConfig: extraConfig, - DeviceChange: deviceSpecs, - NumCPUs: numCPUs, - NumCoresPerSocket: numCoresPerSocket, - MemoryMB: s.providerSpec.MemoryMiB, - }, - Location: types.VirtualMachineRelocateSpec{ - Datastore: types.NewReference(datastore.Reference()), - Folder: types.NewReference(folder.Reference()), - Pool: types.NewReference(resourcepool.Reference()), - DiskMoveType: diskMoveType, - }, - PowerOn: false, // Create powered off machine, for power it on later in "create" procedure - Snapshot: snapshotRef, - } - - task, err := vmTemplate.Clone(s, folder, s.machine.GetName(), spec) - if err != nil { - return "", fmt.Errorf("error triggering clone op for machine %v: %w", s, err) - } - taskVal := task.Reference().Value - klog.V(3).Infof("%v: running task: %+v", s.machine.GetName(), taskVal) - return taskVal, nil -} - -func modifyVMGroup(s *machineScope, delete bool) error { - vmRef, err := findVM(s) - if err != nil { - if isNotFound(err) { - return fmt.Errorf("virtual machine %s was not found: %w", s.machine.Name, err) - } - return fmt.Errorf("error finding virtual machine: %w", err) - } - - rp, err := s.session.Finder.ResourcePool(s.Context, s.providerSpec.Workspace.ResourcePool) - if err != nil { - return fmt.Errorf("error getting resource pool %s: %w", s.providerSpec.Workspace.ResourcePool, err) - } - - ownerRef, err := rp.Owner(s.Context) - if err != nil { - return fmt.Errorf("error getting cluster owner reference from resource pool %s: %w", s.providerSpec.Workspace.ResourcePool, err) - } - - var ccr *object.ClusterComputeResource - var ok bool - if ccr, ok = ownerRef.(*object.ClusterComputeResource); !ok { - return fmt.Errorf("error getting cluster from resource pool %s: %w", s.providerSpec.Workspace.ResourcePool, err) - } - - clusterConfig, err := ccr.Configuration(s.Context) - if err != nil { - return fmt.Errorf("error getting cluster %s configuration: %w", s.providerSpec.Workspace.ResourcePool, err) - } - - var clusterVmGroup *types.ClusterVmGroup - - for _, g := range clusterConfig.Group { - if vmg, ok := g.(*types.ClusterVmGroup); ok { - if vmg.Name == s.providerSpec.Workspace.VMGroup { - clusterVmGroup = vmg - break - } - } - } - - switch { - case clusterVmGroup == nil: - clusterVmGroup = &types.ClusterVmGroup{ - Vm: []types.ManagedObjectReference{vmRef}, - } - case slices.Contains(clusterVmGroup.Vm, vmRef) && delete: - clusterVmGroup.Vm = slices.DeleteFunc(clusterVmGroup.Vm, func(ref types.ManagedObjectReference) bool { - return vmRef.Value == ref.Value - }) - case !slices.Contains(clusterVmGroup.Vm, vmRef): - clusterVmGroup.Vm = append(clusterVmGroup.Vm, vmRef) - default: - return nil - } - - clusterConfigSpec := &types.ClusterConfigSpecEx{ - GroupSpec: []types.ClusterGroupSpec{ - { - ArrayUpdateSpec: types.ArrayUpdateSpec{ - Operation: types.ArrayUpdateOperation("edit"), - }, - Info: &types.ClusterVmGroup{ - ClusterGroupInfo: types.ClusterGroupInfo{ - Name: s.providerSpec.Workspace.VMGroup, - }, - Vm: clusterVmGroup.Vm, - }, - }, - }, - } - - clusterTask, err := ccr.Reconfigure(s.Context, clusterConfigSpec, true) - if err != nil { - return fmt.Errorf("error reconfiguring cluster %s for vm-host group %s: %w", ccr.Name(), clusterVmGroup.Name, err) - } - - return clusterTask.Wait(s.Context) -} - -func powerOn(s *machineScope) (string, error) { - vmRef, err := findVM(s) - if err != nil { - if !isNotFound(err) { - return "", err - } - return "", fmt.Errorf("vm not found during creation for powering on: %w", err) - } - - datacenter := s.session.Datacenter - if datacenter == nil { // if there is no dataceneter, fallback to old powerOn method via vm object - vm := &virtualMachine{ - Context: s.Context, - Obj: object.NewVirtualMachine(s.session.Client.Client, vmRef), - Ref: vmRef, - } - - return vm.powerOnVM() - } - - overrideDRS := &types.OptionValue{ - Key: string(types.ClusterPowerOnVmOptionOverrideAutomationLevel), - Value: string(types.DrsBehaviorFullyAutomated), - } - task, err := datacenter.PowerOnVM(s.Context, []types.ManagedObjectReference{vmRef}, overrideDRS) - if err != nil { - return "", fmt.Errorf("error powering on %s vm: %w", s.machine.Name, err) - } - return task.Reference().Value, nil -} - -func getDiskSpec(s *machineScope, devices object.VirtualDeviceList) (types.BaseVirtualDeviceConfigSpec, error) { - disks := devices.SelectByType((*types.VirtualDisk)(nil)) - if len(disks) != 1 { - return nil, fmt.Errorf("invalid disk count: %d", len(disks)) - } - - disk := disks[0].(*types.VirtualDisk) - cloneCapacityKB := int64(s.providerSpec.DiskGiB) * 1024 * 1024 - if disk.CapacityInKB > cloneCapacityKB { - return nil, machinecontroller.InvalidMachineConfiguration( - "can't resize template disk down, initial capacity is larger: %dKiB > %dKiB", - disk.CapacityInKB, cloneCapacityKB) - } - disk.CapacityInKB = cloneCapacityKB - - return &types.VirtualDeviceConfigSpec{ - Operation: types.VirtualDeviceConfigSpecOperationEdit, - Device: disk, - }, nil -} - -func createDataDisks(s *machineScope, devices object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) { - var diskSpecs []types.BaseVirtualDeviceConfigSpec - - // Only add additional disks if the feature gate is enabled. - if len(s.providerSpec.DataDisks) > 0 && !s.featureGates.Enabled(featuregate.Feature(apifeatures.FeatureGateVSphereMultiDisk)) { - return nil, machinecontroller.InvalidMachineConfiguration( - "machines cannot contain additional disks due to VSphereMultiDisk feature gate being disabled") - } - - // Get primary disk - disks := devices.SelectByType((*types.VirtualDisk)(nil)) - if len(disks) == 0 { - return nil, fmt.Errorf("invalid disk count: %d", len(disks)) - } - - // There is at least one disk - primaryDisk := disks[0].(*types.VirtualDisk) - - // Get the controller of the primary disk. - controller, ok := devices.FindByKey(primaryDisk.ControllerKey).(types.BaseVirtualController) - if !ok { - return nil, fmt.Errorf("unable to find controller with key=%v", primaryDisk.ControllerKey) - } - - controllerKey := controller.GetVirtualController().Key - unitNumberAssigner, err := newUnitNumberAssigner(controller, devices) - if err != nil { - return nil, fmt.Errorf("unable to create unit number assigner: %v", err) - } - - // Let's create the data disks now - for i, dataDisk := range s.providerSpec.DataDisks { - klog.V(2).InfoS("Adding disk", "name", dataDisk.Name, "spec", dataDisk) - - backing := &types.VirtualDiskFlatVer2BackingInfo{ - DiskMode: string(types.VirtualDiskModePersistent), - VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ - FileName: "", - }, - } - - // Set provisioning type for the new data disk. - // Currently, if ThinProvisioned is not set, GOVC will set default to false. We may want to change this behavior - // to match what template image OS disk has configured to make them match if not set. - switch dataDisk.ProvisioningMode { - case machinev1.ProvisioningModeThin: - backing.ThinProvisioned = types.NewBool(true) - case machinev1.ProvisioningModeThick: - backing.ThinProvisioned = types.NewBool(false) - case machinev1.ProvisioningModeEagerlyZeroed: - backing.ThinProvisioned = types.NewBool(false) - backing.EagerlyScrub = types.NewBool(true) - default: - klog.V(2).Infof("No provisioning type detected. Leaving configuration empty.") - } - - dev := &types.VirtualDisk{ - VirtualDevice: types.VirtualDevice{ - // Key needs to be unique and cannot match another new disk being added. So we'll use the index as an - // input to NewKey. NewKey() will always return same value since our new devices are not part of devices yet. - Key: devices.NewKey() - int32(i), - Backing: backing, - ControllerKey: controller.GetVirtualController().Key, - }, - CapacityInKB: int64(dataDisk.SizeGiB) * 1024 * 1024, - } - - vd := dev.GetVirtualDevice() - vd.ControllerKey = controllerKey - - // Assign unit number to the new disk. Should be next available slot on the controller. - unitNumber, err := unitNumberAssigner.assign() - if err != nil { - return nil, err - } - vd.UnitNumber = &unitNumber - - klog.V(2).InfoS("Created device for data disk device", "name", dataDisk.Name, "spec", dataDisk, "device", dev) - diskSpecs = append(diskSpecs, &types.VirtualDeviceConfigSpec{ - Device: dev, - Operation: types.VirtualDeviceConfigSpecOperationAdd, - FileOperation: types.VirtualDeviceConfigSpecFileOperationCreate, - }) - } - - return diskSpecs, nil -} - -type unitNumberAssigner struct { - used []bool - offset int32 -} - -func newUnitNumberAssigner(controller types.BaseVirtualController, existingDevices object.VirtualDeviceList) (*unitNumberAssigner, error) { - if controller == nil { - return nil, errors.New("controller parameter cannot be nil") - } - used := make([]bool, maxUnitNumber) - - // SCSIControllers also use a unit. - if scsiController, ok := controller.(types.BaseVirtualSCSIController); ok { - used[scsiController.GetVirtualSCSIController().ScsiCtlrUnitNumber] = true - } - controllerKey := controller.GetVirtualController().Key - - // Mark all unit numbers of existing devices as used - for _, device := range existingDevices { - d := device.GetVirtualDevice() - if d.ControllerKey == controllerKey && d.UnitNumber != nil { - used[*d.UnitNumber] = true - } - } - - // Set offset to 0, it will auto-increment on the first assignment. - return &unitNumberAssigner{used: used, offset: 0}, nil -} - -func (a *unitNumberAssigner) assign() (int32, error) { - if int(a.offset) > len(a.used) { - return -1, fmt.Errorf("all unit numbers are already in-use") - } - for i, isInUse := range a.used[a.offset:] { - unit := int32(i) + a.offset - if !isInUse { - a.used[unit] = true - a.offset++ - return unit, nil - } - } - return -1, fmt.Errorf("all unit numbers are already in-use") -} - -func getNetworkDevices(s *machineScope, resourcepool *object.ResourcePool, devices object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) { - var networkDevices []types.BaseVirtualDeviceConfigSpec - // Remove any existing NICs - for _, dev := range devices.SelectByType((*types.VirtualEthernetCard)(nil)) { - networkDevices = append(networkDevices, &types.VirtualDeviceConfigSpec{ - Device: dev, - Operation: types.VirtualDeviceConfigSpecOperationRemove, - }) - } - - // Add new NICs based on the machine config. - for i := range s.providerSpec.Network.Devices { - var ccrMo mo.ClusterComputeResource - var backing types.BaseVirtualDeviceBackingInfo - - netSpec := &s.providerSpec.Network.Devices[i] - klog.V(3).Infof("Adding device: %v", netSpec.NetworkName) - - clusterRef, err := resourcepool.Owner(s.Context) - if err != nil { - return nil, fmt.Errorf("unable to find cluster resource: %w", err) - } - - clusterRes := object.NewClusterComputeResource(s.GetSession().Client.Client, clusterRef.Reference()) - err = clusterRes.Properties(s.Context, clusterRef.Reference(), []string{"network"}, &ccrMo) - if err != nil { - return nil, fmt.Errorf("unable to get list of networks in cluster: %w", err) - } - - for _, netRef := range ccrMo.Network { - // Use generic network object to get name - genericNetwork := object.NewNetwork(s.GetSession().Client.Client, netRef) - networkName, err := genericNetwork.ObjectName(s.Context) - if err != nil { - return nil, fmt.Errorf("unable to get network name: %w", err) - } - if netSpec.NetworkName == networkName { - // Use more specific network reference to get Ethernet info - ref := object.NewReference(s.GetSession().Client.Client, netRef) - networkObject, ok := ref.(object.NetworkReference) - if !ok { - return nil, fmt.Errorf("unable to create new ethernet card backing info for network %q: network type failure: %s", netSpec.NetworkName, ref.Reference().Type) - } - - backing, err = networkObject.EthernetCardBackingInfo(s.Context) - if err != nil { - return nil, fmt.Errorf("unable to create new ethernet card backing info for network %q: %w", netSpec.NetworkName, err) - } - break - } - } - - if backing == nil { - return nil, machinecontroller.InvalidMachineConfiguration("unable to get network for %q", netSpec.NetworkName) - } - - dev, err := object.EthernetCardTypes().CreateEthernetCard(ethCardType, backing) - if err != nil { - return nil, fmt.Errorf("unable to create new ethernet card %q for network %q: %w", ethCardType, netSpec.NetworkName, err) - } - - // Get the actual NIC object. This is safe to assert without a check - // because "object.EthernetCardTypes().CreateEthernetCard" returns a - // "types.BaseVirtualEthernetCard" as a "types.BaseVirtualDevice". - nic := dev.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() - // Assign a temporary device key to ensure that a unique one will be - // generated when the device is created. - nic.Key = int32(i) - - networkDevices = append(networkDevices, &types.VirtualDeviceConfigSpec{ - Device: dev, - Operation: types.VirtualDeviceConfigSpecOperationAdd, - }) - klog.V(3).Infof("Adding device: eth card type: %v, network spec: %+v, device info: %+v", - ethCardType, netSpec, dev.GetVirtualDevice().Backing) - } - - return networkDevices, nil -} - -func newVMFlagInfo() *types.VirtualMachineFlagInfo { - diskUUIDEnabled := true - return &types.VirtualMachineFlagInfo{ - DiskUuidEnabled: &diskUUIDEnabled, - } -} - -func taskIsFinished(task *mo.Task) (bool, error) { - if task == nil { - return true, nil - } - - // Otherwise the course of action is determined by the state of the task. - klog.V(3).Infof("task: %v, state: %v, description-id: %v", task.Reference().Value, task.Info.State, task.Info.DescriptionId) - switch task.Info.State { - case types.TaskInfoStateQueued: - return false, nil - case types.TaskInfoStateRunning: - return false, nil - case types.TaskInfoStateSuccess: - return true, nil - case types.TaskInfoStateError: - return true, errors.New(task.Info.Error.LocalizedMessage) - default: - return false, fmt.Errorf("task: %v, unknown state %v", task.Reference().Value, task.Info.State) - } -} - -func setProviderStatus(taskRef string, condition metav1.Condition, scope *machineScope, vm *virtualMachine) error { - klog.Infof("%s: Updating provider status", scope.machine.Name) - - if vm != nil { - id := vm.Obj.UUID(scope.Context) - scope.providerStatus.InstanceID = &id - - // This can return an error if machine is being deleted - powerState, err := vm.getPowerState() - if err != nil { - klog.V(3).Infof("%s: Failed to get power state during provider status update: %v", scope.machine.Name, err) - } else { - powerStateString := string(powerState) - scope.providerStatus.InstanceState = &powerStateString - } - } - - if taskRef != "" { - scope.providerStatus.TaskRef = taskRef - } - - scope.providerStatus.Conditions = setConditions(condition, scope.providerStatus.Conditions) - - return nil -} - -func handleVSphereError(multipleFoundMsg, notFoundMsg string, defaultError, vsphereError error) error { - var multipleFoundError *find.MultipleFoundError - if errors.As(vsphereError, &multipleFoundError) { - return machinecontroller.InvalidMachineConfiguration("%s", multipleFoundMsg) - } - - var notFoundError *find.NotFoundError - if errors.As(vsphereError, ¬FoundError) { - return machinecontroller.InvalidMachineConfiguration("%s", notFoundMsg) - } - - return defaultError -} - -type virtualMachine struct { - context.Context - Ref types.ManagedObjectReference - Obj *object.VirtualMachine -} - -// getHostSystemAncestors looks up and returns vm's host system ancestors, such as "Cluster" and "Datacenter". -// Host system is using there because in vCenter cluster is an ancestor of the hypervisor host but not the vm. -func (vm *virtualMachine) getHostSystemAncestors() ([]mo.ManagedEntity, error) { - client := vm.Obj.Client() - pc := client.ServiceContent.PropertyCollector - - host, err := vm.Obj.HostSystem(vm.Context) - if err != nil { - return nil, err - } - - return mo.Ancestors(vm.Context, client, pc, host.Reference()) -} - -// getRegionAndZone checks the virtual machine and each of its ancestors for the -// given region and zone labels and returns their values if found. -func (vm *virtualMachine) getRegionAndZone(tagsMgr *session.CachingTagsManager, regionLabel, zoneLabel string) (map[string]string, error) { - result := make(map[string]string) - - objects, err := vm.getHostSystemAncestors() - if err != nil { - klog.Errorf("Failed to get ancestors for %s: %v", vm.Ref, err) - return nil, err - } - - for i := range objects { - obj := objects[len(objects)-1-i] // Reverse order. - klog.V(4).Infof("getRegionAndZone: Name: %s, Type: %s", - obj.Self.Value, obj.Self.Type) - - tags, err := tagsMgr.ListAttachedTags(vm.Context, obj) - if err != nil { - klog.Warningf("Failed to list attached tags: %v", err) - return nil, err - } - - for _, value := range tags { - tag, err := tagsMgr.GetTag(vm.Context, value) - if err != nil { - klog.Errorf("Failed to get tag: %v", err) - return nil, err - } - - category, err := tagsMgr.GetCategory(vm.Context, tag.CategoryID) - if err != nil { - klog.Errorf("Failed to get tag category: %v", err) - return nil, err - } - - switch { - case regionLabel != "" && category.Name == regionLabel: - result[regionKey] = tag.Name - klog.V(2).Infof("%s has region tag (%s) with value %s", - vm.Ref, category.Name, tag.Name) - - case zoneLabel != "" && category.Name == zoneLabel: - result[zoneKey] = tag.Name - klog.V(2).Infof("%s has zone tag (%s) with value %s", - vm.Ref, category.Name, tag.Name) - } - - // We've found both tags, return early. - if result[regionKey] != "" && result[zoneKey] != "" { - return result, nil - } - } - } - - return result, nil -} - -func (vm *virtualMachine) powerOnVM() (string, error) { - task, err := vm.Obj.PowerOn(vm.Context) - if err != nil { - return "", err - } - return task.Reference().Value, nil -} - -func (vm *virtualMachine) powerOffVM() (string, error) { - task, err := vm.Obj.PowerOff(vm.Context) - if err != nil { - return "", err - } - return task.Reference().Value, nil -} - -func (vm *virtualMachine) getPowerState() (types.VirtualMachinePowerState, error) { - powerState, err := vm.Obj.PowerState(vm.Context) - if err != nil { - return "", err - } - - switch powerState { - case types.VirtualMachinePowerStatePoweredOn: - return types.VirtualMachinePowerStatePoweredOn, nil - case types.VirtualMachinePowerStatePoweredOff: - return types.VirtualMachinePowerStatePoweredOff, nil - case types.VirtualMachinePowerStateSuspended: - return types.VirtualMachinePowerStateSuspended, nil - default: - return "", fmt.Errorf("unexpected power state %q for vm %v", powerState, vm) - } -} - -// reconcileTags ensures that the required tags are present on the virtual machine, eg the Cluster ID -// that is used by the installer on cluster deletion to ensure ther are no leaked resources. -func (vm *virtualMachine) reconcileTags(ctx context.Context, sessionInstance *session.Session, machine *machinev1.Machine, providerSpec *machinev1.VSphereMachineProviderSpec) error { - if err := sessionInstance.WithCachingTagsManager(vm.Context, func(c *session.CachingTagsManager) error { - klog.Infof("%v: Reconciling attached tags", machine.GetName()) - - clusterID := machine.Labels[machinev1.MachineClusterIDLabel] - tagIDs := []string{clusterID} - tagIDs = append(tagIDs, providerSpec.TagIDs...) - klog.Infof("%v: Reconciling %s tags to vm", machine.GetName(), tagIDs) - for _, tagID := range tagIDs { - attached, err := vm.checkAttachedTag(ctx, tagID, c) - if err != nil { - return err - } - - if !attached { - klog.Infof("%v: Attaching %s tag to vm", machine.GetName(), tagID) - // the tag should already be created by installer or the administrator - if err := c.AttachTag(ctx, tagID, vm.Ref); err != nil { - return err - } - } - } - return nil - }); err != nil { - return err - } - - return nil -} - -// checkAttachedTag returns true if tag is already attached to a vm or tag doesn't exist -func (vm *virtualMachine) checkAttachedTag(ctx context.Context, tagName string, m *session.CachingTagsManager) (bool, error) { - // cluster ID tag doesn't exists in UPI, we should skip tag attachment if it's not found - foundTag, err := vm.foundTag(ctx, tagName, m) - if err != nil { - return false, err - } - - if !foundTag { - return true, nil - } - - tags, err := m.GetAttachedTags(ctx, vm.Ref) - if err != nil { - return false, err - } - - for _, tag := range tags { - if session.IsName(tagName) { - if tag.Name == tagName { - return true, nil - } - } else { - if tag.ID == tagName { - return true, nil - } - } - - } - - return false, nil -} - -// tagToCategoryName converts the tag name to the category name based upon the format set up by the installer. -// Note this is only valid in IPI clusters as typically a UPI cluster won't have the cluster ID tag, in which case the -// controller skips tag creation. -// Ref: https://github.com/openshift/installer/blob/f912534f12491721e3874e2bf64f7fa8d44aa7f5/data/data/vsphere/pre-bootstrap/main.tf#L57 -// Ref: https://github.com/openshift/installer/blob/f912534f12491721e3874e2bf64f7fa8d44aa7f5/pkg/destroy/vsphere/vsphere.go#L231 -func tagToCategoryName(tagName string) string { - return fmt.Sprintf("openshift-%s", tagName) -} - -func (vm *virtualMachine) foundTag(ctx context.Context, tagName string, m *session.CachingTagsManager) (bool, error) { - var tags []string - var err error - - if session.IsName(tagName) { - tags, err = m.ListTagsForCategory(ctx, tagToCategoryName(tagName)) - if err != nil { - if isNotFoundErr(err) { - return false, nil - } - return false, err - } - } else { - tags = []string{tagName} - } - klog.V(4).Infof("validating the presence of tags: %+v", tags) - for _, id := range tags { - tag, err := m.GetTag(ctx, id) - if err != nil { - return false, err - } - if session.IsName(tagName) { - if tag.Name == tagName { - return true, nil - } - } else { - if tag.ID == tagName { - return true, nil - } - } - } - - return false, nil -} - -type NetworkStatus struct { - // Connected is a flag that indicates whether this network is currently - // connected to the VM. - Connected bool - - // IPAddrs is one or more IP addresses reported by vm-tools. - IPAddrs []string - - // MACAddr is the MAC address of the network device. - MACAddr string - - // NetworkName is the name of the network. - NetworkName string -} - -func (vm *virtualMachine) getNetworkStatusList(client *vim25.Client) ([]NetworkStatus, error) { - var obj mo.VirtualMachine - var pc = property.DefaultCollector(client) - var props = []string{ - "config.hardware.device", - "guest.net", - } - - if err := pc.RetrieveOne(vm.Context, vm.Ref, props, &obj); err != nil { - return nil, fmt.Errorf("unable to fetch props %v for vm %v: %w", props, vm.Ref, err) - } - klog.V(3).Infof("Getting network status: object reference: %v", obj.Reference().Value) - if obj.Config == nil { - return nil, errors.New("config.hardware.device is nil") - } - - var networkStatusList []NetworkStatus - for _, device := range obj.Config.Hardware.Device { - if dev, ok := device.(types.BaseVirtualEthernetCard); ok { - nic := dev.GetVirtualEthernetCard() - klog.V(3).Infof("Getting network status: device: %v, macAddress: %v", nic.DeviceInfo.GetDescription().Summary, nic.MacAddress) - netStatus := NetworkStatus{ - MACAddr: nic.MacAddress, - } - if obj.Guest != nil { - klog.V(3).Infof("Getting network status: getting guest info") - for _, i := range obj.Guest.Net { - klog.V(3).Infof("Getting network status: getting guest info: network: %+v", i) - if strings.EqualFold(nic.MacAddress, i.MacAddress) { - //TODO: sanitizeIPAddrs - netStatus.IPAddrs = i.IpAddress - netStatus.NetworkName = i.Network - netStatus.Connected = i.Connected - } - } - } - networkStatusList = append(networkStatusList, netStatus) - } - } - - return networkStatusList, nil -} - -type attachedDisk struct { - device *types.VirtualDisk - fileName string - diskMode string -} - -// Filters out disks that look like vm OS disk or any of the additional disks. -// VM os disks filename contains the machine name in it -// and has the format like "[DATASTORE] path-within-datastore/machine-name.vmdk". -// This is based on vSphere behavior, an OS disk file gets a name that equals the target VM name during the clone operation. -func filterOutVmOsDisk(attachedDisks []attachedDisk, machine *machinev1.Machine) []attachedDisk { - var disks []attachedDisk - regex, _ := regexp.Compile(fmt.Sprintf(".*\\/%s(_\\d*)?.vmdk", machine.GetName())) - - for _, disk := range attachedDisks { - if regex.MatchString(disk.fileName) { - continue - } - disks = append(disks, disk) - } - return disks -} - -func (vm *virtualMachine) getAttachedDisks() ([]attachedDisk, error) { - var attachedDiskList []attachedDisk - devices, err := vm.Obj.Device(vm.Context) - if err != nil { - return nil, err - } - - for _, disk := range devices.SelectByType((*types.VirtualDisk)(nil)) { - backingInfo := disk.GetVirtualDevice().Backing.(types.BaseVirtualDeviceFileBackingInfo).(*types.VirtualDiskFlatVer2BackingInfo) - attachedDiskList = append(attachedDiskList, attachedDisk{ - device: disk.(*types.VirtualDisk), - fileName: backingInfo.FileName, - diskMode: backingInfo.DiskMode, - }) - } - - return attachedDiskList, nil -} - -func (vm *virtualMachine) detachDisks(disks []attachedDisk) error { - var errList []error - - for _, disk := range disks { - klog.V(3).Infof("Detaching disk associated with file %v", disk.fileName) - if err := vm.Obj.RemoveDevice(vm.Context, true, disk.device); err != nil { - errList = append(errList, err) - klog.Errorf("Failed to detach disk associated with file %v ", disk.fileName) - } else { - klog.V(3).Infof("Disk associated with file %v has been detached", disk.fileName) - } - } - if len(errList) > 0 { - return apimachineryutilerrors.NewAggregate(errList) - } - return nil -} - -// IgnitionConfig returns a slice of option values that set the given data as -// the guest's ignition config. -func IgnitionConfig(data []byte) []types.BaseOptionValue { - config := EncodeIgnitionConfig(data) - - if config == "" { - return nil - } - - return []types.BaseOptionValue{ - &types.OptionValue{ - Key: GuestInfoIgnitionData, - Value: config, - }, - &types.OptionValue{ - Key: GuestInfoIgnitionEncoding, - Value: "base64", - }, - } -} - -// EncodeIgnitionConfig attempts to decode the given data until it looks to be -// plain-text, then returns a base64 encoded version of that plain-text. -func EncodeIgnitionConfig(data []byte) string { - if len(data) == 0 { - return "" - } - - for { - decoded, err := base64.StdEncoding.DecodeString(string(data)) - if err != nil { - break - } - - data = decoded - } - - return base64.StdEncoding.EncodeToString(data) -} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/session/session.go b/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/session/session.go deleted file mode 100644 index 85c9b2276e7..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/session/session.go +++ /dev/null @@ -1,243 +0,0 @@ -/* -Copyright 2019 The Kubernetes 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 session - -import ( - "context" - "errors" - "fmt" - "net/url" - "sync" - "time" - - "github.com/vmware/govmomi/vapi/rest" - "github.com/vmware/govmomi/vapi/tags" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" - - "github.com/google/uuid" - "github.com/vmware/govmomi" - "github.com/vmware/govmomi/find" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/soap" - "k8s.io/klog/v2" -) - -var sessionCache = map[string]Session{} -var sessionMU sync.Mutex - -const ( - managedObjectTypeTask = "Task" - clientTimeout = 15 * time.Second -) - -// Session is a vSphere session with a configured Finder. -type Session struct { - *govmomi.Client - Finder *find.Finder - Datacenter *object.Datacenter - - username string - password string - - sessionKey string -} - -func newClientWithTimeout(ctx context.Context, u *url.URL, insecure bool, timeout time.Duration) (*govmomi.Client, error) { - clientCreateCtx, clientCreateCtxCancel := context.WithTimeout(ctx, timeout) - defer clientCreateCtxCancel() - // It makes call to vcenter during new client creation, so pass context with timeout there. - client, err := govmomi.NewClient(clientCreateCtx, u, insecure) - if err != nil { - return nil, err - } - client.Timeout = timeout - return client, nil -} - -// GetOrCreate gets a cached session or creates a new one if one does not -// already exist. -func GetOrCreate( - ctx context.Context, - server, datacenter, username, password string, insecure bool) (*Session, error) { - - sessionMU.Lock() - defer sessionMU.Unlock() - - sessionKey := server + username + datacenter - if session, ok := sessionCache[sessionKey]; ok { - sessionActive, err := session.SessionManager.SessionIsActive(ctx) - if err != nil { - klog.Errorf("Error performing session check request to vSphere: %v", err) - } - if sessionActive { - return &session, nil - } - } - klog.Infof("No existing vCenter session found, creating new session") - - soapURL, err := soap.ParseURL(server) - if err != nil { - return nil, fmt.Errorf("error parsing vSphere URL %q: %w", server, err) - } - if soapURL == nil { - return nil, fmt.Errorf("error parsing vSphere URL %q", server) - } - - // Set user to nil there for prevent login during client creation. - // See https://github.com/vmware/govmomi/blob/master/client.go#L91 - soapURL.User = nil - client, err := newClientWithTimeout(ctx, soapURL, insecure, clientTimeout) - if err != nil { - return nil, fmt.Errorf("error setting up new vSphere SOAP client: %w", err) - } - // Set up user agent before login for being able to track mapi component in vcenter sessions list - client.UserAgent = "machineAPIvSphereProvider" - if err := client.Login(ctx, url.UserPassword(username, password)); err != nil { - return nil, fmt.Errorf("unable to login to vCenter: %w", err) - } - - session := Session{ - Client: client, - username: username, - password: password, - sessionKey: sessionKey, - } - - session.Finder = find.NewFinder(session.Client.Client, false) - - dc, err := session.Finder.DatacenterOrDefault(ctx, datacenter) - if err != nil { - return nil, fmt.Errorf("unable to find datacenter %q: %w", datacenter, err) - } - session.Datacenter = dc - session.Finder.SetDatacenter(dc) - - // Cache the session. - sessionCache[sessionKey] = session - - return &session, nil -} - -func (s *Session) FindVM(ctx context.Context, UUID, name string) (*object.VirtualMachine, error) { - if !isValidUUID(UUID) { - klog.V(3).Infof("Invalid UUID for VM %q: %s, trying to find by name", name, UUID) - return s.findVMByName(ctx, name) - } - klog.V(3).Infof("Find template by instance uuid: %s", UUID) - ref, err := s.FindRefByInstanceUUID(ctx, UUID) - if ref != nil && err == nil { - return object.NewVirtualMachine(s.Client.Client, ref.Reference()), nil - } - if err != nil { - klog.V(3).Infof("Instance not found by UUID: %s, trying to find by name %q", err, name) - } - return s.findVMByName(ctx, name) -} - -// FindByInstanceUUID finds an object by its instance UUID. -func (s *Session) FindRefByInstanceUUID(ctx context.Context, UUID string) (object.Reference, error) { - return s.findRefByUUID(ctx, UUID, true) -} - -func (s *Session) findRefByUUID(ctx context.Context, UUID string, findByInstanceUUID bool) (object.Reference, error) { - if s.Client == nil { - return nil, errors.New("vSphere client is not initialized") - } - si := object.NewSearchIndex(s.Client.Client) - ref, err := si.FindByUuid(ctx, s.Datacenter, UUID, true, &findByInstanceUUID) - if err != nil { - return nil, fmt.Errorf("error finding object by uuid %q: %w", UUID, err) - } - return ref, nil -} - -func (s *Session) findVMByName(ctx context.Context, ID string) (*object.VirtualMachine, error) { - tpl, err := s.Finder.VirtualMachine(ctx, ID) - if err != nil { - if isNotFound(err) { - return nil, err - } - return nil, fmt.Errorf("unable to find template by name %q: %w", ID, err) - } - return tpl, nil -} - -func isNotFound(err error) bool { - switch err.(type) { - case *find.NotFoundError: - return true - default: - return false - } -} - -func isValidUUID(str string) bool { - _, err := uuid.Parse(str) - return err == nil -} - -func (s *Session) GetTask(ctx context.Context, taskRef string) (*mo.Task, error) { - if taskRef == "" { - return nil, errors.New("taskRef can't be empty") - } - var obj mo.Task - moRef := types.ManagedObjectReference{ - Type: managedObjectTypeTask, - Value: taskRef, - } - if err := s.RetrieveOne(ctx, moRef, []string{"info"}, &obj); err != nil { - return nil, err - } - return &obj, nil -} - -func (s *Session) WithRestClient(ctx context.Context, f func(c *rest.Client) error) error { - c := rest.NewClient(s.Client.Client) - - user := url.UserPassword(s.username, s.password) - if err := c.Login(ctx, user); err != nil { - return err - } - - defer func() { - if err := c.Logout(ctx); err != nil { - klog.Errorf("Failed to logout: %v", err) - } - }() - - return f(c) -} - -func (s *Session) WithCachingTagsManager(ctx context.Context, f func(m *CachingTagsManager) error) error { - c := rest.NewClient(s.Client.Client) - - user := url.UserPassword(s.username, s.password) - if err := c.Login(ctx, user); err != nil { - return err - } - - defer func() { - if err := c.Logout(ctx); err != nil { - klog.Errorf("Failed to logout: %v", err) - } - }() - - m := newTagsCachingClient(tags.NewManager(c), s.sessionKey) - - return f(m) -} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/session/tag_ids_caching_client.go b/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/session/tag_ids_caching_client.go deleted file mode 100644 index d6a053d0bca..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/session/tag_ids_caching_client.go +++ /dev/null @@ -1,241 +0,0 @@ -package session - -import ( - "context" - "fmt" - "net/http" - "strings" - "sync" - "time" - - "github.com/vmware/govmomi/vapi/tags" - - "k8s.io/klog/v2" -) - -const ( - defaultCacheTTL = time.Hour * 12 - - // special value for determine whenever tag or category was found in vCenter during last lookup - notFoundValue = "NOT_FOUND" - notFoundErrMessage = "404 Not Found" -) - -type cachedItem struct { - value string - expiresAt int64 -} - -func (ci cachedItem) expired() bool { - return time.Now().UnixNano() > ci.expiresAt -} - -type cacheMap struct { - internalMap sync.Map -} - -// Set value by the given key with default 12 hours lifetime -func (c *cacheMap) Set(key string, value string) { - c.SetWithTTL(key, value, defaultCacheTTL) -} - -// SetWithTTL sets value by given key with lifetime specified in ttl parameter -func (c *cacheMap) SetWithTTL(key string, value string, ttl time.Duration) { - c.internalMap.Store(key, cachedItem{value: value, expiresAt: time.Now().Add(ttl).UnixNano()}) -} - -// Get value by the given key. Second return parameter indicates whenever value found or not -func (c *cacheMap) Get(key string) (value string, ok bool) { - item, found := c.internalMap.Load(key) - if !found { - return "", false - } - if item.(cachedItem).expired() { - klog.V(4).Infof("cache item with name %s expired, invalidating", key) - c.Delete(key) - return "", false - } - return item.(cachedItem).value, true -} - -// Delete value by the given key -func (c *cacheMap) Delete(key string) { - c.internalMap.Delete(key) -} - -type tagsAndCategoriesCache struct { - tags cacheMap - categories cacheMap -} - -var sessionAnnotatedCache = map[string]*tagsAndCategoriesCache{} -var sessionCacheMU sync.Mutex - -func getOrCreateSessionCache(sessionKey string) *tagsAndCategoriesCache { - sessionCacheMU.Lock() - defer sessionCacheMU.Unlock() - - cache, found := sessionAnnotatedCache[sessionKey] - if !found { - cache = &tagsAndCategoriesCache{} - sessionAnnotatedCache[sessionKey] = cache - return cache - } - return cache -} - -// CachingTagsManager wraps tags.Manager from vSphere SDK for -// cache mapping between tags or categories name and their ids. -// Reasoning behind this is the implementation details of tags/categories lookup by name, -// to find a tag/category by name vSphere SDK gets a list of ids and then makes an additional request -// for every object till it will not find matched names. Such peculiarity causes a huge performance degradation -// within environments with a large number of tags/categories, because in the worst case number of rest requests for -// object lookup might be equal to the number of objects. -// -// See tags.Manager methods for more details: https://github.com/vmware/govmomi/blob/a2fb82dc55a8eb00932233aa8028ce97140df784/vapi/tags/tags.go#L172 -// -// This structure is intended to be used from a Session instance (Session.WithCachingTagsManager method specifically) presented in this module. -type CachingTagsManager struct { - *tags.Manager - - sessionKey string // different vCenters might have a different tags in it -} - -func newTagsCachingClient(tagsManager *tags.Manager, sessionKey string) *CachingTagsManager { - return &CachingTagsManager{ - tagsManager, sessionKey, - } -} - -// IsName returns true if the id is not an urn. -// this method came from vSphere sdk, -// see https://github.com/vmware/govmomi/blob/a2fb82dc55a8eb00932233aa8028ce97140df784/vapi/tags/tags.go#L121 for -// more context. -func IsName(id string) bool { - return !strings.HasPrefix(id, "urn:") -} - -// isObjectNotFoundErr checks if error message contains "Not Found" message. -// vSphere api client does not expose error type, so we can rely only on error message -func isObjectNotFoundErr(err error) bool { - return err != nil && strings.HasSuffix(err.Error(), http.StatusText(http.StatusNotFound)) -} - -// GetTag fetches the tag information for the given identifier. -// The id parameter can be a Tag ID or Tag Name. -// This method shadows original tags.Manager method and caches mapping between -// tag name and its id. In case ID was passed, the original method from tags.Manager would be used. -// -// In case if a tag was not found in vCenter, this would be cached for 12 hours and lookup won't happen till cache expiration. -func (t *CachingTagsManager) GetTag(ctx context.Context, id string) (*tags.Tag, error) { - if !IsName(id) { // if id is passed no cache check needed, use original GetTag method instantly - return t.Manager.GetTag(ctx, id) - } - - cache := getOrCreateSessionCache(t.sessionKey) - cachedTagID, found := cache.tags.Get(id) - if found { - klog.V(4).Infof("tag %s: found cached tag id value", id) - if cachedTagID == notFoundValue { - klog.V(4).Infof("tag %s: cache contains special value indicates that tag was not found when cache was filled, treating as non existed tag", id) - return nil, fmt.Errorf("%s", notFoundErrMessage) - } - - tag, err := t.Manager.GetTag(ctx, cachedTagID) - if err != nil { - if isObjectNotFoundErr(err) { - klog.V(3).Infof("tag %s: tag was not found in vCenter by cached id, invalidating cache", id) - // if tag not found, invalidate the cache and fallback to the default search method - cache.tags.Delete(id) - return t.Manager.GetTag(ctx, id) - } - return tag, err - } - return tag, nil - } - - klog.V(3).Infof("tag %s: tags cache miss, trying to find tag by name, it might take time", id) - tag, err := t.Manager.GetTag(ctx, id) - if err != nil { - if isObjectNotFoundErr(err) { - klog.V(3).Infof("tag %s not found in vCenter, caching", id) - // Caching the fact that tag was not found due to performance issues with lookup tag by name. - // In case when object does not exist amount of requests equals the amount of categories should happen, - // because of vCenter rest api design. - // For more context see vcenter rest api documentation and original method implementation: - // https://developer.vmware.com/apis/vsphere-automation/v7.0U1/cis/rest/com/vmware/cis/tagging/tag/idtag_id/get/ - // https://developer.vmware.com/apis/vsphere-automation/v7.0U1/cis/rest/com/vmware/cis/tagging/tag/get/ - // https://github.com/vmware/govmomi/blob/a2fb82dc55a8eb00932233aa8028ce97140df784/vapi/tags/tags.go#L121 - cache.tags.Set(id, notFoundValue) - } - return tag, err - } - cache.tags.Set(tag.Name, tag.ID) - return tag, err -} - -// GetCategory fetches the category information for the given identifier. -// The id parameter can be a Category ID or Category Name. -// This method shadows original tags.Manager method and caches mapping between -// tag name and its id. In case ID was passed, the original method from tags.Manager would be used. -// -// In case if a tag was not found in vCenter, this would be cached for 12 hours and lookup won't happen till cache expiration. -func (t *CachingTagsManager) GetCategory(ctx context.Context, id string) (*tags.Category, error) { - if !IsName(id) { // if id is passed no cache check needed, use original GetTag method instantly - return t.Manager.GetCategory(ctx, id) - } - - cache := getOrCreateSessionCache(t.sessionKey) - cachedCategoryID, found := cache.categories.Get(id) - if found { - klog.V(4).Infof("category %s: found cached category id value", id) - if cachedCategoryID == notFoundValue { - klog.V(4).Infof("category %s: cache contains special value indicates that tag was not found when cache was filled, treating as non existing category", id) - return nil, fmt.Errorf("%s", notFoundErrMessage) - } - - category, err := t.Manager.GetCategory(ctx, cachedCategoryID) - if err != nil { - if isObjectNotFoundErr(err) { - klog.V(3).Infof("category %s: category was not found in vCenter by cached id, invalidating id cache", id) - cache.categories.Delete(id) // if category not found, invalidate the cache and fallback to the default search method - return t.Manager.GetCategory(ctx, id) - } - return category, err - } - return category, nil - } - - klog.V(3).Infof("category %s: categories cache miss, trying to find category by name, it might take time", id) - category, err := t.Manager.GetCategory(ctx, id) - if err != nil { - if isObjectNotFoundErr(err) { - klog.V(3).Infof("category %s not found in vCenter, caching", id) - // Caching the fact that category was not found due to performance issues with lookup category by name. - // In case when object does not exist amount of requests equals the amount of categories should happen, - // because of vCenter rest api design. - // For more context see vcenter rest api documentation and original method implementation: - // https://developer.vmware.com/apis/vsphere-automation/v7.0U1/cis/rest/com/vmware/cis/tagging/category/idcategory_id/get/ - // https://developer.vmware.com/apis/vsphere-automation/v7.0U1/cis/rest/com/vmware/cis/tagging/category/get/ - // https://github.com/vmware/govmomi/blob/a2fb82dc55a8eb00932233aa8028ce97140df784/vapi/tags/categories.go#L122 - cache.categories.Set(id, notFoundValue) - } - return category, err - } - cache.categories.Set(category.Name, category.ID) - return category, err -} - -// ListTagsForCategory tag ids for the given category. -// The id parameter can be a Category ID or Category Name. -// Uses caching GetCategory method. -func (t *CachingTagsManager) ListTagsForCategory(ctx context.Context, id string) ([]string, error) { - if IsName(id) { - category, err := t.GetCategory(ctx, id) - if err != nil { - return nil, err - } - id = category.ID - } - return t.Manager.ListTagsForCategory(ctx, id) -} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/util.go b/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/util.go deleted file mode 100644 index 8b7f3da8a51..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/controller/vsphere/util.go +++ /dev/null @@ -1,280 +0,0 @@ -package vsphere - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - "strings" - - configv1 "github.com/openshift/api/config/v1" - machinev1 "github.com/openshift/api/machine/v1beta1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/runtime" - vsphere "k8s.io/cloud-provider-vsphere/pkg/common/config" - "k8s.io/klog/v2" - runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - globalInfrastuctureName = "cluster" - OpenshiftConfigNamespace = "openshift-config" -) - -// GetInfrastructure retrieves the Infrastructure object from the provided API reader. -// It returns an error if the API reader is nil or if there's an issue fetching the Infrastructure. -func GetInfrastructure(c runtimeclient.Reader) (*configv1.Infrastructure, error) { - if c == nil { - return nil, errors.New("no API reader -- will not fetch infrastructure config") - } - - infra := &configv1.Infrastructure{} - infraName := runtimeclient.ObjectKey{Name: globalInfrastuctureName} - - if err := c.Get(context.Background(), infraName, infra); err != nil { - return nil, err - } - - return infra, nil -} - -func getVSphereConfig(c runtimeclient.Reader, configNamespace string) (*vsphere.Config, error) { - if c == nil { - return nil, errors.New("no API reader -- will not fetch vSphere config") - } - - infra, err := GetInfrastructure(c) - if err != nil { - return nil, err - } - - if infra.Spec.CloudConfig.Name == "" { - return nil, fmt.Errorf("cluster infrastructure CloudConfig has empty name") - } - - if infra.Spec.CloudConfig.Key == "" { - return nil, fmt.Errorf("cluster infrastructure CloudConfig has empty key") - } - - cm := &corev1.ConfigMap{} - cmName := runtimeclient.ObjectKey{ - Name: infra.Spec.CloudConfig.Name, - Namespace: configNamespace, - } - - if err := c.Get(context.Background(), cmName, cm); err != nil { - return nil, err - } - - cloudConfig, found := cm.Data[infra.Spec.CloudConfig.Key] - if !found { - return nil, fmt.Errorf("cloud-config ConfigMap has no %q key", - infra.Spec.CloudConfig.Key, - ) - } - - return vsphere.ReadConfig([]byte(cloudConfig)) -} - -func setConditions(condition metav1.Condition, conditions []metav1.Condition) []metav1.Condition { - now := metav1.Now() - - if existingCondition := findCondition(conditions, condition.Type); existingCondition == nil { - condition.LastTransitionTime = now - conditions = append(conditions, condition) - } else { - updateExistingCondition(&condition, existingCondition) - } - - return conditions -} - -func findCondition(conditions []metav1.Condition, conditionType string) *metav1.Condition { - for i := range conditions { - if conditions[i].Type == conditionType { - return &conditions[i] - } - } - return nil -} - -func updateExistingCondition(newCondition, existingCondition *metav1.Condition) { - if !shouldUpdateCondition(newCondition, existingCondition) { - return - } - - if existingCondition.Status != newCondition.Status { - existingCondition.LastTransitionTime = metav1.Now() - } - existingCondition.Status = newCondition.Status - existingCondition.Reason = newCondition.Reason - existingCondition.Message = newCondition.Message -} - -func shouldUpdateCondition(newCondition, existingCondition *metav1.Condition) bool { - return newCondition.Reason != existingCondition.Reason || newCondition.Message != existingCondition.Message -} - -func conditionSuccess() metav1.Condition { - return metav1.Condition{ - Type: string(machinev1.MachineCreation), - Status: metav1.ConditionTrue, - Reason: machinev1.MachineCreationSucceededConditionReason, - Message: "Machine successfully created", - } -} - -func conditionFailed() metav1.Condition { - return metav1.Condition{ - Type: string(machinev1.MachineCreation), - Status: metav1.ConditionFalse, - Reason: machinev1.MachineCreationSucceededConditionReason, - } -} - -func getVCenterPortFromConfig(config *vsphere.Config, vcenter string) string { - if config != nil { - for _, vc := range config.VirtualCenter { - if vc.VCenterIP == vcenter { - if len(vc.VCenterPort) > 0 { - return vc.VCenterPort - } else { - return config.Global.VCenterPort - } - } - } - } - return "" -} - -func getVCenterInsecureFlagFromConfig(config *vsphere.Config, vcenter string) bool { - if config != nil { - for _, vc := range config.VirtualCenter { - if vc.VCenterIP == vcenter { - return vc.InsecureFlag - } - } - - // Either vCenter is not found or config is missing. - return config.Global.InsecureFlag - } - - return false -} - -// RawExtensionFromProviderSpec marshals the machine provider spec. -func RawExtensionFromProviderSpec(spec *machinev1.VSphereMachineProviderSpec) (*runtime.RawExtension, error) { - if spec == nil { - return &runtime.RawExtension{}, nil - } - - var rawBytes []byte - var err error - if rawBytes, err = json.Marshal(spec); err != nil { - return nil, fmt.Errorf("error marshalling providerSpec: %v", err) - } - - return &runtime.RawExtension{ - Raw: rawBytes, - }, nil -} - -// RawExtensionFromProviderStatus marshals the provider status -func RawExtensionFromProviderStatus(status *machinev1.VSphereMachineProviderStatus) (*runtime.RawExtension, error) { - if status == nil { - return &runtime.RawExtension{}, nil - } - - var rawBytes []byte - var err error - if rawBytes, err = json.Marshal(status); err != nil { - return nil, fmt.Errorf("error marshalling providerStatus: %v", err) - } - - return &runtime.RawExtension{ - Raw: rawBytes, - }, nil -} - -// ProviderSpecFromRawExtension unmarshals the JSON-encoded spec -func ProviderSpecFromRawExtension(rawExtension *runtime.RawExtension) (*machinev1.VSphereMachineProviderSpec, error) { - if rawExtension == nil { - return &machinev1.VSphereMachineProviderSpec{}, nil - } - - spec := new(machinev1.VSphereMachineProviderSpec) - if err := json.Unmarshal(rawExtension.Raw, &spec); err != nil { - return nil, fmt.Errorf("error unmarshalling providerSpec: %v", err) - } - - klog.V(5).Infof("Got provider spec from raw extension: %+v", spec) - return spec, nil -} - -// ProviderStatusFromRawExtension unmarshals a raw extension into a VSphereMachineProviderStatus type -func ProviderStatusFromRawExtension(rawExtension *runtime.RawExtension) (*machinev1.VSphereMachineProviderStatus, error) { - if rawExtension == nil { - return &machinev1.VSphereMachineProviderStatus{}, nil - } - - providerStatus := new(machinev1.VSphereMachineProviderStatus) - if err := json.Unmarshal(rawExtension.Raw, providerStatus); err != nil { - return nil, fmt.Errorf("error unmarshalling providerStatus: %v", err) - } - - klog.V(5).Infof("Got provider Status from raw extension: %+v", providerStatus) - return providerStatus, nil -} - -// isNotFoundErr checks if error message contains "Not Found" message. -// vSphere api client does not expose error type, so we can rely only on error message -func isNotFoundErr(err error) bool { - return err != nil && strings.HasSuffix(err.Error(), http.StatusText(http.StatusNotFound)) -} - -// podPredicate is a predicate function for filtering PodList -type podPredicate func(corev1.Pod) bool - -// isTerminating is a predicate for determine pods in 'Terminating' state -func isTerminating(p corev1.Pod) bool { - return p.DeletionTimestamp != nil -} - -// filterPods filters a podList and returns a PodList matching passed predicates -func filterPods(podList *corev1.PodList, predicates ...podPredicate) *corev1.PodList { - filteredPods := &corev1.PodList{} - for _, pod := range podList.Items { - var match = true - for _, p := range predicates { - if !p(pod) { - match = false - break - } - } - if match { - filteredPods.Items = append(filteredPods.Items, pod) - } - } - - return filteredPods -} - -// getPodList returns pod list on a given node matching pod predicates -func getPodList(ctx context.Context, apiReader runtimeclient.Reader, n *corev1.Node, filters []podPredicate) (*corev1.PodList, error) { - fieldSelector, err := fields.ParseSelector("spec.nodeName=" + n.Name) - if err != nil { - return nil, err - } - - allPods := &corev1.PodList{} - if err := apiReader.List(ctx, allPods, &runtimeclient.ListOptions{ - FieldSelector: fieldSelector, - }); err != nil { - return nil, err - } - - return filterPods(allPods, filters...), nil -} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/util/ipam/util.go b/vendor/github.com/openshift/machine-api-operator/pkg/util/ipam/util.go deleted file mode 100644 index 81a616e15cd..00000000000 --- a/vendor/github.com/openshift/machine-api-operator/pkg/util/ipam/util.go +++ /dev/null @@ -1,231 +0,0 @@ -package ipam - -import ( - "context" - "fmt" - - machinev1 "github.com/openshift/api/machine/v1beta1" - ipamv1beta1 "sigs.k8s.io/cluster-api/api/ipam/v1beta1" //nolint:staticcheck - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// EnsureIPAddressClaim ensures an IPAddressClaim exists for the given claim name and pool -func EnsureIPAddressClaim( - ctx context.Context, - runtimeClient client.Client, - claimName string, - machine *machinev1.Machine, - pool machinev1.AddressesFromPool) (*ipamv1beta1.IPAddressClaim, error) { - claimKey := client.ObjectKey{ - Namespace: machine.Namespace, - Name: claimName, - } - ipAddressClaim := &ipamv1beta1.IPAddressClaim{} - if err := runtimeClient.Get(ctx, claimKey, ipAddressClaim); err == nil { - // If we found a claim, make sure it has owner field set. - if len(ipAddressClaim.OwnerReferences) == 0 { - klog.Infof("IPAddressClaim %s is missing owner field. Updating to reference machine.", claimName) - _ = AdoptOrphanClaim(ctx, runtimeClient, claimName, machine, ipAddressClaim) - } - return ipAddressClaim, nil - } else if !apierrors.IsNotFound(err) { - return nil, fmt.Errorf("error while getting IP address claim: %w", err) - } - - klog.Infof("creating IPAddressClaim %s", claimName) - gv := machinev1.SchemeGroupVersion - machineRef := metav1.NewControllerRef(machine, gv.WithKind("Machine")) - ipAddressClaim = &ipamv1beta1.IPAddressClaim{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - *machineRef, - }, - Finalizers: []string{ - machinev1.IPClaimProtectionFinalizer, - }, - Name: claimName, - Namespace: machine.Namespace, - }, - Spec: ipamv1beta1.IPAddressClaimSpec{ - PoolRef: corev1.TypedLocalObjectReference{ - APIGroup: &pool.Group, - Kind: pool.Resource, - Name: pool.Name, - }, - }, - } - if err := runtimeClient.Create(ctx, ipAddressClaim); err != nil { - return nil, fmt.Errorf("unable to create IPAddressClaim: %w", err) - } - return ipAddressClaim, nil -} - -// AdoptOrphanClaim updates the IPAddressClaim to belong to the specified machine. -func AdoptOrphanClaim( - ctx context.Context, - runtimeClient client.Client, - claimName string, - machine *machinev1.Machine, - ipAddressClaim *ipamv1beta1.IPAddressClaim) error { - gv := machinev1.SchemeGroupVersion - machineRef := metav1.NewControllerRef(machine, gv.WithKind("Machine")) - ipAddressClaim.OwnerReferences = []metav1.OwnerReference{ - *machineRef, - } - if err := runtimeClient.Update(ctx, ipAddressClaim); err != nil { - klog.Warningf("Unable to adopt orphaned IPAddressClaim %v: %v", claimName, err) - return err - } - return nil -} - -// CountOutstandingIPAddressClaimsForMachine determines the number of outstanding IP address claims a machine is waiting -// to be fulfilled. -func CountOutstandingIPAddressClaimsForMachine( - ctx context.Context, - runtimeClient client.Client, - ipAddressClaims []ipamv1beta1.IPAddressClaim) int { - fulfilledClaimCount := 0 - - for _, claim := range ipAddressClaims { - if len(claim.Status.AddressRef.Name) > 0 { - fulfilledClaimCount++ - } - } - - return len(ipAddressClaims) - fulfilledClaimCount -} - -// RetrieveBoundIPAddress retrieves the IPAddress which is bound to the named IPAddressClaim -func RetrieveBoundIPAddress( - ctx context.Context, - runtimeClient client.Client, - machine *machinev1.Machine, - claimName string) (*ipamv1beta1.IPAddress, error) { - - claimKey := client.ObjectKey{ - Namespace: machine.Namespace, - Name: claimName, - } - ipAddressClaim := &ipamv1beta1.IPAddressClaim{} - if err := runtimeClient.Get(ctx, claimKey, ipAddressClaim); err != nil { - return nil, fmt.Errorf("unable to get IPAddressClaim: %w", err) - } - - if len(ipAddressClaim.Status.AddressRef.Name) == 0 { - return nil, fmt.Errorf("no IPAddress is bound to claim %s", claimName) - } - - ipAddress := &ipamv1beta1.IPAddress{} - addressKey := client.ObjectKey{ - Namespace: machine.Namespace, - Name: ipAddressClaim.Status.AddressRef.Name, - } - if err := runtimeClient.Get(ctx, addressKey, ipAddress); err != nil { - return nil, fmt.Errorf("unable to get IPAddress: %w", err) - } - return ipAddress, nil -} - -func RemoveFinalizersForIPAddressClaims( - ctx context.Context, - runtimeClient client.Client, - machine machinev1.Machine) error { - ipAddressClaimList := &ipamv1beta1.IPAddressClaimList{} - if err := runtimeClient.List(ctx, ipAddressClaimList, client.InNamespace(machine.Namespace)); err != nil { - return fmt.Errorf("unable to list IPAddressClaims: %w", err) - } - - for _, ipAddressClaim := range ipAddressClaimList.Items { - if metav1.IsControlledBy(&ipAddressClaim, &machine) { - finalizers := sets.NewString(ipAddressClaim.ObjectMeta.Finalizers...) - if !finalizers.Has(machinev1.IPClaimProtectionFinalizer) { - continue - } - finalizers.Delete(machinev1.IPClaimProtectionFinalizer) - ipAddressClaim.ObjectMeta.Finalizers = finalizers.List() - if err := runtimeClient.Update(ctx, &ipAddressClaim); err != nil { - return fmt.Errorf("unable to update IPAddressClaim: %w", err) - } - } - } - return nil -} - -// HasStaticIPConfiguration returns true if the specified machine has an address pool -func HasStaticIPConfiguration(providerSpec *machinev1.VSphereMachineProviderSpec) bool { - for _, device := range providerSpec.Network.Devices { - if len(device.Gateway) > 0 || - len(device.IPAddrs) > 0 || - len(device.Nameservers) > 0 || - len(device.AddressesFromPools) > 0 { - return true - } - } - return false -} - -// GetIPAddressClaimName returns a consistently named claim name -func GetIPAddressClaimName(machine *machinev1.Machine, deviceIdx int, poolIdx int) string { - return fmt.Sprintf("%s-claim-%d-%d", machine.Name, deviceIdx, poolIdx) -} - -// HasOutstandingIPAddressClaims checks to see if a given machine has outstanding IP address claims -func HasOutstandingIPAddressClaims( - ctx context.Context, - runtimeClient client.Client, - machine *machinev1.Machine, - networkDevices []machinev1.NetworkDeviceSpec, -) (int, error) { - var associatedClaims []ipamv1beta1.IPAddressClaim - for deviceIdx, networkDevice := range networkDevices { - for poolIdx, addressPool := range networkDevice.AddressesFromPools { - claimName := GetIPAddressClaimName(machine, deviceIdx, poolIdx) - claim, err := EnsureIPAddressClaim( - ctx, - runtimeClient, - claimName, - machine, - addressPool) - if err != nil { - return -1, fmt.Errorf("error while ensuring IPAddressClaim exists: %w", err) - } - associatedClaims = append(associatedClaims, *claim) - } - } - - if len(associatedClaims) > 0 { - outstandingClaims := CountOutstandingIPAddressClaimsForMachine(ctx, runtimeClient, associatedClaims) - return outstandingClaims, nil - } - return 0, nil -} - -// VerifyIPAddressOwners verifies that each IPAddress associated with the machine has the owner set. -func VerifyIPAddressOwners( - ctx context.Context, - runtimeClient client.Client, - machine *machinev1.Machine, - networkDevices []machinev1.NetworkDeviceSpec) error { - for deviceIdx, networkDevice := range networkDevices { - for poolIdx, addressPool := range networkDevice.AddressesFromPools { - claimName := GetIPAddressClaimName(machine, deviceIdx, poolIdx) - _, err := EnsureIPAddressClaim( - ctx, - runtimeClient, - claimName, - machine, - addressPool) - if err != nil { - return fmt.Errorf("error while ensuring IPAddressClaim exists: %w", err) - } - } - } - return nil -} diff --git a/vendor/gopkg.in/gcfg.v1/LICENSE b/vendor/gopkg.in/gcfg.v1/LICENSE deleted file mode 100644 index 87a5cede339..00000000000 --- a/vendor/gopkg.in/gcfg.v1/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go -Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/gcfg.v1/README b/vendor/gopkg.in/gcfg.v1/README deleted file mode 100644 index 1ff233a529d..00000000000 --- a/vendor/gopkg.in/gcfg.v1/README +++ /dev/null @@ -1,4 +0,0 @@ -Gcfg reads INI-style configuration files into Go structs; -supports user-defined types and subsections. - -Package docs: https://godoc.org/gopkg.in/gcfg.v1 diff --git a/vendor/gopkg.in/gcfg.v1/doc.go b/vendor/gopkg.in/gcfg.v1/doc.go deleted file mode 100644 index 32f3e9d69c4..00000000000 --- a/vendor/gopkg.in/gcfg.v1/doc.go +++ /dev/null @@ -1,145 +0,0 @@ -// Package gcfg reads "INI-style" text-based configuration files with -// "name=value" pairs grouped into sections (gcfg files). -// -// This package is still a work in progress; see the sections below for planned -// changes. -// -// Syntax -// -// The syntax is based on that used by git config: -// http://git-scm.com/docs/git-config#_syntax . -// There are some (planned) differences compared to the git config format: -// - improve data portability: -// - must be encoded in UTF-8 (for now) and must not contain the 0 byte -// - include and "path" type is not supported -// (path type may be implementable as a user-defined type) -// - internationalization -// - section and variable names can contain unicode letters, unicode digits -// (as defined in http://golang.org/ref/spec#Characters ) and hyphens -// (U+002D), starting with a unicode letter -// - disallow potentially ambiguous or misleading definitions: -// - `[sec.sub]` format is not allowed (deprecated in gitconfig) -// - `[sec ""]` is not allowed -// - use `[sec]` for section name "sec" and empty subsection name -// - (planned) within a single file, definitions must be contiguous for each: -// - section: '[secA]' -> '[secB]' -> '[secA]' is an error -// - subsection: '[sec "A"]' -> '[sec "B"]' -> '[sec "A"]' is an error -// - multivalued variable: 'multi=a' -> 'other=x' -> 'multi=b' is an error -// -// Data structure -// -// The functions in this package read values into a user-defined struct. -// Each section corresponds to a struct field in the config struct, and each -// variable in a section corresponds to a data field in the section struct. -// The mapping of each section or variable name to fields is done either based -// on the "gcfg" struct tag or by matching the name of the section or variable, -// ignoring case. In the latter case, hyphens '-' in section and variable names -// correspond to underscores '_' in field names. -// Fields must be exported; to use a section or variable name starting with a -// letter that is neither upper- or lower-case, prefix the field name with 'X'. -// (See https://code.google.com/p/go/issues/detail?id=5763#c4 .) -// -// For sections with subsections, the corresponding field in config must be a -// map, rather than a struct, with string keys and pointer-to-struct values. -// Values for subsection variables are stored in the map with the subsection -// name used as the map key. -// (Note that unlike section and variable names, subsection names are case -// sensitive.) -// When using a map, and there is a section with the same section name but -// without a subsection name, its values are stored with the empty string used -// as the key. -// It is possible to provide default values for subsections in the section -// "default-" (or by setting values in the corresponding struct -// field "Default_"). -// -// The functions in this package panic if config is not a pointer to a struct, -// or when a field is not of a suitable type (either a struct or a map with -// string keys and pointer-to-struct values). -// -// Parsing of values -// -// The section structs in the config struct may contain single-valued or -// multi-valued variables. Variables of unnamed slice type (that is, a type -// starting with `[]`) are treated as multi-value; all others (including named -// slice types) are treated as single-valued variables. -// -// Single-valued variables are handled based on the type as follows. -// Unnamed pointer types (that is, types starting with `*`) are dereferenced, -// and if necessary, a new instance is allocated. -// -// For types implementing the encoding.TextUnmarshaler interface, the -// UnmarshalText method is used to set the value. Implementing this method is -// the recommended way for parsing user-defined types. -// -// For fields of string kind, the value string is assigned to the field, after -// unquoting and unescaping as needed. -// For fields of bool kind, the field is set to true if the value is "true", -// "yes", "on" or "1", and set to false if the value is "false", "no", "off" or -// "0", ignoring case. In addition, single-valued bool fields can be specified -// with a "blank" value (variable name without equals sign and value); in such -// case the value is set to true. -// -// Predefined integer types [u]int(|8|16|32|64) and big.Int are parsed as -// decimal or hexadecimal (if having '0x' prefix). (This is to prevent -// unintuitively handling zero-padded numbers as octal.) Other types having -// [u]int* as the underlying type, such as os.FileMode and uintptr allow -// decimal, hexadecimal, or octal values. -// Parsing mode for integer types can be overridden using the struct tag option -// ",int=mode" where mode is a combination of the 'd', 'h', and 'o' characters -// (each standing for decimal, hexadecimal, and octal, respectively.) -// -// All other types are parsed using fmt.Sscanf with the "%v" verb. -// -// For multi-valued variables, each individual value is parsed as above and -// appended to the slice. If the first value is specified as a "blank" value -// (variable name without equals sign and value), a new slice is allocated; -// that is any values previously set in the slice will be ignored. -// -// The types subpackage for provides helpers for parsing "enum-like" and integer -// types. -// -// Error handling -// -// There are 3 types of errors: -// -// - programmer errors / panics: -// - invalid configuration structure -// - data errors: -// - fatal errors: -// - invalid configuration syntax -// - warnings: -// - data that doesn't belong to any part of the config structure -// -// Programmer errors trigger panics. These are should be fixed by the programmer -// before releasing code that uses gcfg. -// -// Data errors cause gcfg to return a non-nil error value. This includes the -// case when there are extra unknown key-value definitions in the configuration -// data (extra data). -// However, in some occasions it is desirable to be able to proceed in -// situations when the only data error is that of extra data. -// These errors are handled at a different (warning) priority and can be -// filtered out programmatically. To ignore extra data warnings, wrap the -// gcfg.Read*Into invocation into a call to gcfg.FatalOnly. -// -// TODO -// -// The following is a list of changes under consideration: -// - documentation -// - self-contained syntax documentation -// - more practical examples -// - move TODOs to issue tracker (eventually) -// - syntax -// - reconsider valid escape sequences -// (gitconfig doesn't support \r in value, \t in subsection name, etc.) -// - reading / parsing gcfg files -// - define internal representation structure -// - support multiple inputs (readers, strings, files) -// - support declaring encoding (?) -// - support varying fields sets for subsections (?) -// - writing gcfg files -// - error handling -// - make error context accessible programmatically? -// - limit input size? -// -package gcfg // import "gopkg.in/gcfg.v1" diff --git a/vendor/gopkg.in/gcfg.v1/errors.go b/vendor/gopkg.in/gcfg.v1/errors.go deleted file mode 100644 index 83a591dac74..00000000000 --- a/vendor/gopkg.in/gcfg.v1/errors.go +++ /dev/null @@ -1,57 +0,0 @@ -package gcfg - -import warnings "gopkg.in/warnings.v0" - -// FatalOnly filters the results of a Read*Into invocation and returns only -// fatal errors. That is, errors (warnings) indicating data for unknown -// sections / variables is ignored. Example invocation: -// -// err := gcfg.FatalOnly(gcfg.ReadFileInto(&cfg, configFile)) -// if err != nil { -// ... -// -func FatalOnly(err error) error { - return warnings.FatalOnly(err) -} - -func isFatal(err error) bool { - _, ok := err.(extraData) - return !ok -} - -type loc struct { - section string - subsection *string - variable *string -} - -type extraData struct { - loc -} - -type locErr struct { - msg string - loc -} - -func (l loc) String() string { - s := "section \"" + l.section + "\"" - if l.subsection != nil { - s += ", subsection \"" + *l.subsection + "\"" - } - if l.variable != nil { - s += ", variable \"" + *l.variable + "\"" - } - return s -} - -func (e extraData) Error() string { - return "can't store data at " + e.loc.String() -} - -func (e locErr) Error() string { - return e.msg + " at " + e.loc.String() -} - -var _ error = extraData{} -var _ error = locErr{} diff --git a/vendor/gopkg.in/gcfg.v1/read.go b/vendor/gopkg.in/gcfg.v1/read.go deleted file mode 100644 index 06796653cc2..00000000000 --- a/vendor/gopkg.in/gcfg.v1/read.go +++ /dev/null @@ -1,257 +0,0 @@ -package gcfg - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - - "gopkg.in/gcfg.v1/scanner" - "gopkg.in/gcfg.v1/token" - "gopkg.in/warnings.v0" -) - -var unescape = map[rune]rune{'\\': '\\', '"': '"', 'n': '\n', 't': '\t'} -var utf8Bom = []byte("\ufeff") - -// no error: invalid literals should be caught by scanner -func unquote(s string) string { - u, q, esc := make([]rune, 0, len(s)), false, false - for _, c := range s { - if esc { - uc, ok := unescape[c] - switch { - case ok: - u = append(u, uc) - fallthrough - case !q && c == '\n': - esc = false - continue - } - panic("invalid escape sequence") - } - switch c { - case '"': - q = !q - case '\\': - esc = true - default: - u = append(u, c) - } - } - if q { - panic("missing end quote") - } - if esc { - panic("invalid escape sequence") - } - return string(u) -} - -func readIntoPass(c *warnings.Collector, config interface{}, fset *token.FileSet, - file *token.File, src []byte, subsectPass bool) error { - // - var s scanner.Scanner - var errs scanner.ErrorList - s.Init(file, src, func(p token.Position, m string) { errs.Add(p, m) }, 0) - sect, sectsub := "", "" - pos, tok, lit := s.Scan() - errfn := func(msg string) error { - return fmt.Errorf("%s: %s", fset.Position(pos), msg) - } - for { - if errs.Len() > 0 { - if err := c.Collect(errs.Err()); err != nil { - return err - } - } - switch tok { - case token.EOF: - return nil - case token.EOL, token.COMMENT: - pos, tok, lit = s.Scan() - case token.LBRACK: - pos, tok, lit = s.Scan() - if errs.Len() > 0 { - if err := c.Collect(errs.Err()); err != nil { - return err - } - } - if tok != token.IDENT { - if err := c.Collect(errfn("expected section name")); err != nil { - return err - } - } - sect, sectsub = lit, "" - pos, tok, lit = s.Scan() - if errs.Len() > 0 { - if err := c.Collect(errs.Err()); err != nil { - return err - } - } - if tok == token.STRING { - sectsub = unquote(lit) - if sectsub == "" { - if err := c.Collect(errfn("empty subsection name")); err != nil { - return err - } - } - pos, tok, lit = s.Scan() - if errs.Len() > 0 { - if err := c.Collect(errs.Err()); err != nil { - return err - } - } - } - if tok != token.RBRACK { - if sectsub == "" { - if err := c.Collect(errfn("expected subsection name or right bracket")); err != nil { - return err - } - } - if err := c.Collect(errfn("expected right bracket")); err != nil { - return err - } - } - pos, tok, lit = s.Scan() - if tok != token.EOL && tok != token.EOF && tok != token.COMMENT { - if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil { - return err - } - } - // If a section/subsection header was found, ensure a - // container object is created, even if there are no - // variables further down. - err := c.Collect(set(c, config, sect, sectsub, "", true, "", subsectPass)) - if err != nil { - return err - } - case token.IDENT: - if sect == "" { - if err := c.Collect(errfn("expected section header")); err != nil { - return err - } - } - n := lit - pos, tok, lit = s.Scan() - if errs.Len() > 0 { - return errs.Err() - } - blank, v := tok == token.EOF || tok == token.EOL || tok == token.COMMENT, "" - if !blank { - if tok != token.ASSIGN { - if err := c.Collect(errfn("expected '='")); err != nil { - return err - } - } - pos, tok, lit = s.Scan() - if errs.Len() > 0 { - if err := c.Collect(errs.Err()); err != nil { - return err - } - } - if tok != token.STRING { - if err := c.Collect(errfn("expected value")); err != nil { - return err - } - } - v = unquote(lit) - pos, tok, lit = s.Scan() - if errs.Len() > 0 { - if err := c.Collect(errs.Err()); err != nil { - return err - } - } - if tok != token.EOL && tok != token.EOF && tok != token.COMMENT { - if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil { - return err - } - } - } - err := set(c, config, sect, sectsub, n, blank, v, subsectPass) - if err != nil { - return err - } - default: - if sect == "" { - if err := c.Collect(errfn("expected section header")); err != nil { - return err - } - } - if err := c.Collect(errfn("expected section header or variable declaration")); err != nil { - return err - } - } - } -} - -func readInto(config interface{}, fset *token.FileSet, file *token.File, - src []byte) error { - // - c := warnings.NewCollector(isFatal) - err := readIntoPass(c, config, fset, file, src, false) - if err != nil { - return err - } - err = readIntoPass(c, config, fset, file, src, true) - if err != nil { - return err - } - return c.Done() -} - -// ReadInto reads gcfg formatted data from reader and sets the values into the -// corresponding fields in config. -func ReadInto(config interface{}, reader io.Reader) error { - src, err := ioutil.ReadAll(reader) - if err != nil { - return err - } - fset := token.NewFileSet() - file := fset.AddFile("", fset.Base(), len(src)) - return readInto(config, fset, file, src) -} - -// ReadStringInto reads gcfg formatted data from str and sets the values into -// the corresponding fields in config. -func ReadStringInto(config interface{}, str string) error { - r := strings.NewReader(str) - return ReadInto(config, r) -} - -// ReadFileInto reads gcfg formatted data from the file filename and sets the -// values into the corresponding fields in config. -// -// For compatibility with files created on Windows, the ReadFileInto skips a -// single leading UTF8 BOM sequence if it exists. -func ReadFileInto(config interface{}, filename string) error { - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - src, err := ioutil.ReadAll(f) - if err != nil { - return err - } - - // Skips a single leading UTF8 BOM sequence if it exists. - src = skipLeadingUtf8Bom(src) - - fset := token.NewFileSet() - file := fset.AddFile(filename, fset.Base(), len(src)) - return readInto(config, fset, file, src) -} - -func skipLeadingUtf8Bom(src []byte) []byte { - lengthUtf8Bom := len(utf8Bom) - - if len(src) >= lengthUtf8Bom { - if bytes.Equal(src[:lengthUtf8Bom], utf8Bom) { - return src[lengthUtf8Bom:] - } - } - return src -} diff --git a/vendor/gopkg.in/gcfg.v1/scanner/errors.go b/vendor/gopkg.in/gcfg.v1/scanner/errors.go deleted file mode 100644 index 1a3c0f6563c..00000000000 --- a/vendor/gopkg.in/gcfg.v1/scanner/errors.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package scanner - -import ( - "fmt" - "io" - "sort" -) - -import ( - "gopkg.in/gcfg.v1/token" -) - -// In an ErrorList, an error is represented by an *Error. -// The position Pos, if valid, points to the beginning of -// the offending token, and the error condition is described -// by Msg. -// -type Error struct { - Pos token.Position - Msg string -} - -// Error implements the error interface. -func (e Error) Error() string { - if e.Pos.Filename != "" || e.Pos.IsValid() { - // don't print "" - // TODO(gri) reconsider the semantics of Position.IsValid - return e.Pos.String() + ": " + e.Msg - } - return e.Msg -} - -// ErrorList is a list of *Errors. -// The zero value for an ErrorList is an empty ErrorList ready to use. -// -type ErrorList []*Error - -// Add adds an Error with given position and error message to an ErrorList. -func (p *ErrorList) Add(pos token.Position, msg string) { - *p = append(*p, &Error{pos, msg}) -} - -// Reset resets an ErrorList to no errors. -func (p *ErrorList) Reset() { *p = (*p)[0:0] } - -// ErrorList implements the sort Interface. -func (p ErrorList) Len() int { return len(p) } -func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -func (p ErrorList) Less(i, j int) bool { - e := &p[i].Pos - f := &p[j].Pos - if e.Filename < f.Filename { - return true - } - if e.Filename == f.Filename { - return e.Offset < f.Offset - } - return false -} - -// Sort sorts an ErrorList. *Error entries are sorted by position, -// other errors are sorted by error message, and before any *Error -// entry. -// -func (p ErrorList) Sort() { - sort.Sort(p) -} - -// RemoveMultiples sorts an ErrorList and removes all but the first error per line. -func (p *ErrorList) RemoveMultiples() { - sort.Sort(p) - var last token.Position // initial last.Line is != any legal error line - i := 0 - for _, e := range *p { - if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line { - last = e.Pos - (*p)[i] = e - i++ - } - } - (*p) = (*p)[0:i] -} - -// An ErrorList implements the error interface. -func (p ErrorList) Error() string { - switch len(p) { - case 0: - return "no errors" - case 1: - return p[0].Error() - } - return fmt.Sprintf("%s (and %d more errors)", p[0], len(p)-1) -} - -// Err returns an error equivalent to this error list. -// If the list is empty, Err returns nil. -func (p ErrorList) Err() error { - if len(p) == 0 { - return nil - } - return p -} - -// PrintError is a utility function that prints a list of errors to w, -// one error per line, if the err parameter is an ErrorList. Otherwise -// it prints the err string. -// -func PrintError(w io.Writer, err error) { - if list, ok := err.(ErrorList); ok { - for _, e := range list { - fmt.Fprintf(w, "%s\n", e) - } - } else if err != nil { - fmt.Fprintf(w, "%s\n", err) - } -} diff --git a/vendor/gopkg.in/gcfg.v1/scanner/scanner.go b/vendor/gopkg.in/gcfg.v1/scanner/scanner.go deleted file mode 100644 index 6d0eee916cc..00000000000 --- a/vendor/gopkg.in/gcfg.v1/scanner/scanner.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package scanner implements a scanner for gcfg configuration text. -// It takes a []byte as source which can then be tokenized -// through repeated calls to the Scan method. -// -// Note that the API for the scanner package may change to accommodate new -// features or implementation changes in gcfg. -// -package scanner - -import ( - "fmt" - "path/filepath" - "unicode" - "unicode/utf8" -) - -import ( - "gopkg.in/gcfg.v1/token" -) - -// An ErrorHandler may be provided to Scanner.Init. If a syntax error is -// encountered and a handler was installed, the handler is called with a -// position and an error message. The position points to the beginning of -// the offending token. -// -type ErrorHandler func(pos token.Position, msg string) - -// A Scanner holds the scanner's internal state while processing -// a given text. It can be allocated as part of another data -// structure but must be initialized via Init before use. -// -type Scanner struct { - // immutable state - file *token.File // source file handle - dir string // directory portion of file.Name() - src []byte // source - err ErrorHandler // error reporting; or nil - mode Mode // scanning mode - - // scanning state - ch rune // current character - offset int // character offset - rdOffset int // reading offset (position after current character) - lineOffset int // current line offset - nextVal bool // next token is expected to be a value - - // public state - ok to modify - ErrorCount int // number of errors encountered -} - -// Read the next Unicode char into s.ch. -// s.ch < 0 means end-of-file. -// -func (s *Scanner) next() { - if s.rdOffset < len(s.src) { - s.offset = s.rdOffset - if s.ch == '\n' { - s.lineOffset = s.offset - s.file.AddLine(s.offset) - } - r, w := rune(s.src[s.rdOffset]), 1 - switch { - case r == 0: - s.error(s.offset, "illegal character NUL") - case r >= 0x80: - // not ASCII - r, w = utf8.DecodeRune(s.src[s.rdOffset:]) - if r == utf8.RuneError && w == 1 { - s.error(s.offset, "illegal UTF-8 encoding") - } - } - s.rdOffset += w - s.ch = r - } else { - s.offset = len(s.src) - if s.ch == '\n' { - s.lineOffset = s.offset - s.file.AddLine(s.offset) - } - s.ch = -1 // eof - } -} - -// A mode value is a set of flags (or 0). -// They control scanner behavior. -// -type Mode uint - -const ( - ScanComments Mode = 1 << iota // return comments as COMMENT tokens -) - -// Init prepares the scanner s to tokenize the text src by setting the -// scanner at the beginning of src. The scanner uses the file set file -// for position information and it adds line information for each line. -// It is ok to re-use the same file when re-scanning the same file as -// line information which is already present is ignored. Init causes a -// panic if the file size does not match the src size. -// -// Calls to Scan will invoke the error handler err if they encounter a -// syntax error and err is not nil. Also, for each error encountered, -// the Scanner field ErrorCount is incremented by one. The mode parameter -// determines how comments are handled. -// -// Note that Init may call err if there is an error in the first character -// of the file. -// -func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) { - // Explicitly initialize all fields since a scanner may be reused. - if file.Size() != len(src) { - panic(fmt.Sprintf("file size (%d) does not match src len (%d)", file.Size(), len(src))) - } - s.file = file - s.dir, _ = filepath.Split(file.Name()) - s.src = src - s.err = err - s.mode = mode - - s.ch = ' ' - s.offset = 0 - s.rdOffset = 0 - s.lineOffset = 0 - s.ErrorCount = 0 - s.nextVal = false - - s.next() -} - -func (s *Scanner) error(offs int, msg string) { - if s.err != nil { - s.err(s.file.Position(s.file.Pos(offs)), msg) - } - s.ErrorCount++ -} - -func (s *Scanner) scanComment() string { - // initial [;#] already consumed - offs := s.offset - 1 // position of initial [;#] - - for s.ch != '\n' && s.ch >= 0 { - s.next() - } - return string(s.src[offs:s.offset]) -} - -func isLetter(ch rune) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch >= 0x80 && unicode.IsLetter(ch) -} - -func isDigit(ch rune) bool { - return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) -} - -func (s *Scanner) scanIdentifier() string { - offs := s.offset - for isLetter(s.ch) || isDigit(s.ch) || s.ch == '-' { - s.next() - } - return string(s.src[offs:s.offset]) -} - -func (s *Scanner) scanEscape(val bool) { - offs := s.offset - ch := s.ch - s.next() // always make progress - switch ch { - case '\\', '"': - // ok - case 'n', 't': - if val { - break // ok - } - fallthrough - default: - s.error(offs, "unknown escape sequence") - } -} - -func (s *Scanner) scanString() string { - // '"' opening already consumed - offs := s.offset - 1 - - for s.ch != '"' { - ch := s.ch - s.next() - if ch == '\n' || ch < 0 { - s.error(offs, "string not terminated") - break - } - if ch == '\\' { - s.scanEscape(false) - } - } - - s.next() - - return string(s.src[offs:s.offset]) -} - -func stripCR(b []byte) []byte { - c := make([]byte, len(b)) - i := 0 - for _, ch := range b { - if ch != '\r' { - c[i] = ch - i++ - } - } - return c[:i] -} - -func (s *Scanner) scanValString() string { - offs := s.offset - - hasCR := false - end := offs - inQuote := false -loop: - for inQuote || s.ch >= 0 && s.ch != '\n' && s.ch != ';' && s.ch != '#' { - ch := s.ch - s.next() - switch { - case inQuote && ch == '\\': - s.scanEscape(true) - case !inQuote && ch == '\\': - if s.ch == '\r' { - hasCR = true - s.next() - } - if s.ch != '\n' && s.ch != '"' { - s.error(offs, "unquoted '\\' must be followed by new line or double quote") - break loop - } - s.next() - case ch == '"': - inQuote = !inQuote - case ch == '\r': - hasCR = true - case ch < 0 || inQuote && ch == '\n': - s.error(offs, "string not terminated") - break loop - } - if inQuote || !isWhiteSpace(ch) { - end = s.offset - } - } - - lit := s.src[offs:end] - if hasCR { - lit = stripCR(lit) - } - - return string(lit) -} - -func isWhiteSpace(ch rune) bool { - return ch == ' ' || ch == '\t' || ch == '\r' -} - -func (s *Scanner) skipWhitespace() { - for isWhiteSpace(s.ch) { - s.next() - } -} - -// Scan scans the next token and returns the token position, the token, -// and its literal string if applicable. The source end is indicated by -// token.EOF. -// -// If the returned token is a literal (token.IDENT, token.STRING) or -// token.COMMENT, the literal string has the corresponding value. -// -// If the returned token is token.ILLEGAL, the literal string is the -// offending character. -// -// In all other cases, Scan returns an empty literal string. -// -// For more tolerant parsing, Scan will return a valid token if -// possible even if a syntax error was encountered. Thus, even -// if the resulting token sequence contains no illegal tokens, -// a client may not assume that no error occurred. Instead it -// must check the scanner's ErrorCount or the number of calls -// of the error handler, if there was one installed. -// -// Scan adds line information to the file added to the file -// set with Init. Token positions are relative to that file -// and thus relative to the file set. -// -func (s *Scanner) Scan() (pos token.Pos, tok token.Token, lit string) { -scanAgain: - s.skipWhitespace() - - // current token start - pos = s.file.Pos(s.offset) - - // determine token value - switch ch := s.ch; { - case s.nextVal: - lit = s.scanValString() - tok = token.STRING - s.nextVal = false - case isLetter(ch): - lit = s.scanIdentifier() - tok = token.IDENT - default: - s.next() // always make progress - switch ch { - case -1: - tok = token.EOF - case '\n': - tok = token.EOL - case '"': - tok = token.STRING - lit = s.scanString() - case '[': - tok = token.LBRACK - case ']': - tok = token.RBRACK - case ';', '#': - // comment - lit = s.scanComment() - if s.mode&ScanComments == 0 { - // skip comment - goto scanAgain - } - tok = token.COMMENT - case '=': - tok = token.ASSIGN - s.nextVal = true - default: - s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch)) - tok = token.ILLEGAL - lit = string(ch) - } - } - - return -} diff --git a/vendor/gopkg.in/gcfg.v1/set.go b/vendor/gopkg.in/gcfg.v1/set.go deleted file mode 100644 index 73aee500357..00000000000 --- a/vendor/gopkg.in/gcfg.v1/set.go +++ /dev/null @@ -1,329 +0,0 @@ -package gcfg - -import ( - "bytes" - "encoding" - "encoding/gob" - "fmt" - "math/big" - "reflect" - "strings" - "unicode" - "unicode/utf8" - - "gopkg.in/gcfg.v1/types" - "gopkg.in/warnings.v0" -) - -type tag struct { - ident string - intMode string -} - -func newTag(ts string) tag { - t := tag{} - s := strings.Split(ts, ",") - t.ident = s[0] - for _, tse := range s[1:] { - if strings.HasPrefix(tse, "int=") { - t.intMode = tse[len("int="):] - } - } - return t -} - -func fieldFold(v reflect.Value, name string) (reflect.Value, tag) { - var n string - r0, _ := utf8.DecodeRuneInString(name) - if unicode.IsLetter(r0) && !unicode.IsLower(r0) && !unicode.IsUpper(r0) { - n = "X" - } - n += strings.Replace(name, "-", "_", -1) - f, ok := v.Type().FieldByNameFunc(func(fieldName string) bool { - if !v.FieldByName(fieldName).CanSet() { - return false - } - f, _ := v.Type().FieldByName(fieldName) - t := newTag(f.Tag.Get("gcfg")) - if t.ident != "" { - return strings.EqualFold(t.ident, name) - } - return strings.EqualFold(n, fieldName) - }) - if !ok { - return reflect.Value{}, tag{} - } - return v.FieldByName(f.Name), newTag(f.Tag.Get("gcfg")) -} - -type setter func(destp interface{}, blank bool, val string, t tag) error - -var errUnsupportedType = fmt.Errorf("unsupported type") -var errBlankUnsupported = fmt.Errorf("blank value not supported for type") - -var setters = []setter{ - typeSetter, textUnmarshalerSetter, kindSetter, scanSetter, -} - -func textUnmarshalerSetter(d interface{}, blank bool, val string, t tag) error { - dtu, ok := d.(encoding.TextUnmarshaler) - if !ok { - return errUnsupportedType - } - if blank { - return errBlankUnsupported - } - return dtu.UnmarshalText([]byte(val)) -} - -func boolSetter(d interface{}, blank bool, val string, t tag) error { - if blank { - reflect.ValueOf(d).Elem().Set(reflect.ValueOf(true)) - return nil - } - b, err := types.ParseBool(val) - if err == nil { - reflect.ValueOf(d).Elem().Set(reflect.ValueOf(b)) - } - return err -} - -func intMode(mode string) types.IntMode { - var m types.IntMode - if strings.ContainsAny(mode, "dD") { - m |= types.Dec - } - if strings.ContainsAny(mode, "hH") { - m |= types.Hex - } - if strings.ContainsAny(mode, "oO") { - m |= types.Oct - } - return m -} - -var typeModes = map[reflect.Type]types.IntMode{ - reflect.TypeOf(int(0)): types.Dec | types.Hex, - reflect.TypeOf(int8(0)): types.Dec | types.Hex, - reflect.TypeOf(int16(0)): types.Dec | types.Hex, - reflect.TypeOf(int32(0)): types.Dec | types.Hex, - reflect.TypeOf(int64(0)): types.Dec | types.Hex, - reflect.TypeOf(uint(0)): types.Dec | types.Hex, - reflect.TypeOf(uint8(0)): types.Dec | types.Hex, - reflect.TypeOf(uint16(0)): types.Dec | types.Hex, - reflect.TypeOf(uint32(0)): types.Dec | types.Hex, - reflect.TypeOf(uint64(0)): types.Dec | types.Hex, - // use default mode (allow dec/hex/oct) for uintptr type - reflect.TypeOf(big.Int{}): types.Dec | types.Hex, -} - -func intModeDefault(t reflect.Type) types.IntMode { - m, ok := typeModes[t] - if !ok { - m = types.Dec | types.Hex | types.Oct - } - return m -} - -func intSetter(d interface{}, blank bool, val string, t tag) error { - if blank { - return errBlankUnsupported - } - mode := intMode(t.intMode) - if mode == 0 { - mode = intModeDefault(reflect.TypeOf(d).Elem()) - } - return types.ParseInt(d, val, mode) -} - -func stringSetter(d interface{}, blank bool, val string, t tag) error { - if blank { - return errBlankUnsupported - } - dsp, ok := d.(*string) - if !ok { - return errUnsupportedType - } - *dsp = val - return nil -} - -var kindSetters = map[reflect.Kind]setter{ - reflect.String: stringSetter, - reflect.Bool: boolSetter, - reflect.Int: intSetter, - reflect.Int8: intSetter, - reflect.Int16: intSetter, - reflect.Int32: intSetter, - reflect.Int64: intSetter, - reflect.Uint: intSetter, - reflect.Uint8: intSetter, - reflect.Uint16: intSetter, - reflect.Uint32: intSetter, - reflect.Uint64: intSetter, - reflect.Uintptr: intSetter, -} - -var typeSetters = map[reflect.Type]setter{ - reflect.TypeOf(big.Int{}): intSetter, -} - -func typeSetter(d interface{}, blank bool, val string, tt tag) error { - t := reflect.ValueOf(d).Type().Elem() - setter, ok := typeSetters[t] - if !ok { - return errUnsupportedType - } - return setter(d, blank, val, tt) -} - -func kindSetter(d interface{}, blank bool, val string, tt tag) error { - k := reflect.ValueOf(d).Type().Elem().Kind() - setter, ok := kindSetters[k] - if !ok { - return errUnsupportedType - } - return setter(d, blank, val, tt) -} - -func scanSetter(d interface{}, blank bool, val string, tt tag) error { - if blank { - return errBlankUnsupported - } - return types.ScanFully(d, val, 'v') -} - -func newValue(c *warnings.Collector, sect string, vCfg reflect.Value, - vType reflect.Type) (reflect.Value, error) { - // - pv := reflect.New(vType) - dfltName := "default-" + sect - dfltField, _ := fieldFold(vCfg, dfltName) - var err error - if dfltField.IsValid() { - b := bytes.NewBuffer(nil) - ge := gob.NewEncoder(b) - if err = c.Collect(ge.EncodeValue(dfltField)); err != nil { - return pv, err - } - gd := gob.NewDecoder(bytes.NewReader(b.Bytes())) - if err = c.Collect(gd.DecodeValue(pv.Elem())); err != nil { - return pv, err - } - } - return pv, nil -} - -func set(c *warnings.Collector, cfg interface{}, sect, sub, name string, - blank bool, value string, subsectPass bool) error { - // - vPCfg := reflect.ValueOf(cfg) - if vPCfg.Kind() != reflect.Ptr || vPCfg.Elem().Kind() != reflect.Struct { - panic(fmt.Errorf("config must be a pointer to a struct")) - } - vCfg := vPCfg.Elem() - vSect, _ := fieldFold(vCfg, sect) - l := loc{section: sect} - if !vSect.IsValid() { - err := extraData{loc: l} - return c.Collect(err) - } - isSubsect := vSect.Kind() == reflect.Map - if subsectPass != isSubsect { - return nil - } - if isSubsect { - l.subsection = &sub - vst := vSect.Type() - if vst.Key().Kind() != reflect.String || - vst.Elem().Kind() != reflect.Ptr || - vst.Elem().Elem().Kind() != reflect.Struct { - panic(fmt.Errorf("map field for section must have string keys and "+ - " pointer-to-struct values: section %q", sect)) - } - if vSect.IsNil() { - vSect.Set(reflect.MakeMap(vst)) - } - k := reflect.ValueOf(sub) - pv := vSect.MapIndex(k) - if !pv.IsValid() { - vType := vSect.Type().Elem().Elem() - var err error - if pv, err = newValue(c, sect, vCfg, vType); err != nil { - return err - } - vSect.SetMapIndex(k, pv) - } - vSect = pv.Elem() - } else if vSect.Kind() != reflect.Struct { - panic(fmt.Errorf("field for section must be a map or a struct: "+ - "section %q", sect)) - } else if sub != "" { - return c.Collect(extraData{loc: l}) - } - // Empty name is a special value, meaning that only the - // section/subsection object is to be created, with no values set. - if name == "" { - return nil - } - vVar, t := fieldFold(vSect, name) - l.variable = &name - if !vVar.IsValid() { - return c.Collect(extraData{loc: l}) - } - // vVal is either single-valued var, or newly allocated value within multi-valued var - var vVal reflect.Value - // multi-value if unnamed slice type - isMulti := vVar.Type().Name() == "" && vVar.Kind() == reflect.Slice || - vVar.Type().Name() == "" && vVar.Kind() == reflect.Ptr && vVar.Type().Elem().Name() == "" && vVar.Type().Elem().Kind() == reflect.Slice - if isMulti && vVar.Kind() == reflect.Ptr { - if vVar.IsNil() { - vVar.Set(reflect.New(vVar.Type().Elem())) - } - vVar = vVar.Elem() - } - if isMulti && blank { - vVar.Set(reflect.Zero(vVar.Type())) - return nil - } - if isMulti { - vVal = reflect.New(vVar.Type().Elem()).Elem() - } else { - vVal = vVar - } - isDeref := vVal.Type().Name() == "" && vVal.Type().Kind() == reflect.Ptr - isNew := isDeref && vVal.IsNil() - // vAddr is address of value to set (dereferenced & allocated as needed) - var vAddr reflect.Value - switch { - case isNew: - vAddr = reflect.New(vVal.Type().Elem()) - case isDeref && !isNew: - vAddr = vVal - default: - vAddr = vVal.Addr() - } - vAddrI := vAddr.Interface() - err, ok := error(nil), false - for _, s := range setters { - err = s(vAddrI, blank, value, t) - if err == nil { - ok = true - break - } - if err != errUnsupportedType { - return locErr{msg: err.Error(), loc: l} - } - } - if !ok { - // in case all setters returned errUnsupportedType - return locErr{msg: err.Error(), loc: l} - } - if isNew { // set reference if it was dereferenced and newly allocated - vVal.Set(vAddr) - } - if isMulti { // append if multi-valued - vVar.Set(reflect.Append(vVar, vVal)) - } - return nil -} diff --git a/vendor/gopkg.in/gcfg.v1/token/position.go b/vendor/gopkg.in/gcfg.v1/token/position.go deleted file mode 100644 index fc45c1e7693..00000000000 --- a/vendor/gopkg.in/gcfg.v1/token/position.go +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO(gri) consider making this a separate package outside the go directory. - -package token - -import ( - "fmt" - "sort" - "sync" -) - -// ----------------------------------------------------------------------------- -// Positions - -// Position describes an arbitrary source position -// including the file, line, and column location. -// A Position is valid if the line number is > 0. -// -type Position struct { - Filename string // filename, if any - Offset int // offset, starting at 0 - Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) -} - -// IsValid returns true if the position is valid. -func (pos *Position) IsValid() bool { return pos.Line > 0 } - -// String returns a string in one of several forms: -// -// file:line:column valid position with file name -// line:column valid position without file name -// file invalid position with file name -// - invalid position without file name -// -func (pos Position) String() string { - s := pos.Filename - if pos.IsValid() { - if s != "" { - s += ":" - } - s += fmt.Sprintf("%d:%d", pos.Line, pos.Column) - } - if s == "" { - s = "-" - } - return s -} - -// Pos is a compact encoding of a source position within a file set. -// It can be converted into a Position for a more convenient, but much -// larger, representation. -// -// The Pos value for a given file is a number in the range [base, base+size], -// where base and size are specified when adding the file to the file set via -// AddFile. -// -// To create the Pos value for a specific source offset, first add -// the respective file to the current file set (via FileSet.AddFile) -// and then call File.Pos(offset) for that file. Given a Pos value p -// for a specific file set fset, the corresponding Position value is -// obtained by calling fset.Position(p). -// -// Pos values can be compared directly with the usual comparison operators: -// If two Pos values p and q are in the same file, comparing p and q is -// equivalent to comparing the respective source file offsets. If p and q -// are in different files, p < q is true if the file implied by p was added -// to the respective file set before the file implied by q. -// -type Pos int - -// The zero value for Pos is NoPos; there is no file and line information -// associated with it, and NoPos().IsValid() is false. NoPos is always -// smaller than any other Pos value. The corresponding Position value -// for NoPos is the zero value for Position. -// -const NoPos Pos = 0 - -// IsValid returns true if the position is valid. -func (p Pos) IsValid() bool { - return p != NoPos -} - -// ----------------------------------------------------------------------------- -// File - -// A File is a handle for a file belonging to a FileSet. -// A File has a name, size, and line offset table. -// -type File struct { - set *FileSet - name string // file name as provided to AddFile - base int // Pos value range for this file is [base...base+size] - size int // file size as provided to AddFile - - // lines and infos are protected by set.mutex - lines []int - infos []lineInfo -} - -// Name returns the file name of file f as registered with AddFile. -func (f *File) Name() string { - return f.name -} - -// Base returns the base offset of file f as registered with AddFile. -func (f *File) Base() int { - return f.base -} - -// Size returns the size of file f as registered with AddFile. -func (f *File) Size() int { - return f.size -} - -// LineCount returns the number of lines in file f. -func (f *File) LineCount() int { - f.set.mutex.RLock() - n := len(f.lines) - f.set.mutex.RUnlock() - return n -} - -// AddLine adds the line offset for a new line. -// The line offset must be larger than the offset for the previous line -// and smaller than the file size; otherwise the line offset is ignored. -// -func (f *File) AddLine(offset int) { - f.set.mutex.Lock() - if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size { - f.lines = append(f.lines, offset) - } - f.set.mutex.Unlock() -} - -// SetLines sets the line offsets for a file and returns true if successful. -// The line offsets are the offsets of the first character of each line; -// for instance for the content "ab\nc\n" the line offsets are {0, 3}. -// An empty file has an empty line offset table. -// Each line offset must be larger than the offset for the previous line -// and smaller than the file size; otherwise SetLines fails and returns -// false. -// -func (f *File) SetLines(lines []int) bool { - // verify validity of lines table - size := f.size - for i, offset := range lines { - if i > 0 && offset <= lines[i-1] || size <= offset { - return false - } - } - - // set lines table - f.set.mutex.Lock() - f.lines = lines - f.set.mutex.Unlock() - return true -} - -// SetLinesForContent sets the line offsets for the given file content. -func (f *File) SetLinesForContent(content []byte) { - var lines []int - line := 0 - for offset, b := range content { - if line >= 0 { - lines = append(lines, line) - } - line = -1 - if b == '\n' { - line = offset + 1 - } - } - - // set lines table - f.set.mutex.Lock() - f.lines = lines - f.set.mutex.Unlock() -} - -// A lineInfo object describes alternative file and line number -// information (such as provided via a //line comment in a .go -// file) for a given file offset. -type lineInfo struct { - // fields are exported to make them accessible to gob - Offset int - Filename string - Line int -} - -// AddLineInfo adds alternative file and line number information for -// a given file offset. The offset must be larger than the offset for -// the previously added alternative line info and smaller than the -// file size; otherwise the information is ignored. -// -// AddLineInfo is typically used to register alternative position -// information for //line filename:line comments in source files. -// -func (f *File) AddLineInfo(offset int, filename string, line int) { - f.set.mutex.Lock() - if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size { - f.infos = append(f.infos, lineInfo{offset, filename, line}) - } - f.set.mutex.Unlock() -} - -// Pos returns the Pos value for the given file offset; -// the offset must be <= f.Size(). -// f.Pos(f.Offset(p)) == p. -// -func (f *File) Pos(offset int) Pos { - if offset > f.size { - panic("illegal file offset") - } - return Pos(f.base + offset) -} - -// Offset returns the offset for the given file position p; -// p must be a valid Pos value in that file. -// f.Offset(f.Pos(offset)) == offset. -// -func (f *File) Offset(p Pos) int { - if int(p) < f.base || int(p) > f.base+f.size { - panic("illegal Pos value") - } - return int(p) - f.base -} - -// Line returns the line number for the given file position p; -// p must be a Pos value in that file or NoPos. -// -func (f *File) Line(p Pos) int { - // TODO(gri) this can be implemented much more efficiently - return f.Position(p).Line -} - -func searchLineInfos(a []lineInfo, x int) int { - return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1 -} - -// info returns the file name, line, and column number for a file offset. -func (f *File) info(offset int) (filename string, line, column int) { - filename = f.name - if i := searchInts(f.lines, offset); i >= 0 { - line, column = i+1, offset-f.lines[i]+1 - } - if len(f.infos) > 0 { - // almost no files have extra line infos - if i := searchLineInfos(f.infos, offset); i >= 0 { - alt := &f.infos[i] - filename = alt.Filename - if i := searchInts(f.lines, alt.Offset); i >= 0 { - line += alt.Line - i - 1 - } - } - } - return -} - -func (f *File) position(p Pos) (pos Position) { - offset := int(p) - f.base - pos.Offset = offset - pos.Filename, pos.Line, pos.Column = f.info(offset) - return -} - -// Position returns the Position value for the given file position p; -// p must be a Pos value in that file or NoPos. -// -func (f *File) Position(p Pos) (pos Position) { - if p != NoPos { - if int(p) < f.base || int(p) > f.base+f.size { - panic("illegal Pos value") - } - pos = f.position(p) - } - return -} - -// ----------------------------------------------------------------------------- -// FileSet - -// A FileSet represents a set of source files. -// Methods of file sets are synchronized; multiple goroutines -// may invoke them concurrently. -// -type FileSet struct { - mutex sync.RWMutex // protects the file set - base int // base offset for the next file - files []*File // list of files in the order added to the set - last *File // cache of last file looked up -} - -// NewFileSet creates a new file set. -func NewFileSet() *FileSet { - s := new(FileSet) - s.base = 1 // 0 == NoPos - return s -} - -// Base returns the minimum base offset that must be provided to -// AddFile when adding the next file. -// -func (s *FileSet) Base() int { - s.mutex.RLock() - b := s.base - s.mutex.RUnlock() - return b - -} - -// AddFile adds a new file with a given filename, base offset, and file size -// to the file set s and returns the file. Multiple files may have the same -// name. The base offset must not be smaller than the FileSet's Base(), and -// size must not be negative. -// -// Adding the file will set the file set's Base() value to base + size + 1 -// as the minimum base value for the next file. The following relationship -// exists between a Pos value p for a given file offset offs: -// -// int(p) = base + offs -// -// with offs in the range [0, size] and thus p in the range [base, base+size]. -// For convenience, File.Pos may be used to create file-specific position -// values from a file offset. -// -func (s *FileSet) AddFile(filename string, base, size int) *File { - s.mutex.Lock() - defer s.mutex.Unlock() - if base < s.base || size < 0 { - panic("illegal base or size") - } - // base >= s.base && size >= 0 - f := &File{s, filename, base, size, []int{0}, nil} - base += size + 1 // +1 because EOF also has a position - if base < 0 { - panic("token.Pos offset overflow (> 2G of source code in file set)") - } - // add the file to the file set - s.base = base - s.files = append(s.files, f) - s.last = f - return f -} - -// Iterate calls f for the files in the file set in the order they were added -// until f returns false. -// -func (s *FileSet) Iterate(f func(*File) bool) { - for i := 0; ; i++ { - var file *File - s.mutex.RLock() - if i < len(s.files) { - file = s.files[i] - } - s.mutex.RUnlock() - if file == nil || !f(file) { - break - } - } -} - -func searchFiles(a []*File, x int) int { - return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 -} - -func (s *FileSet) file(p Pos) *File { - // common case: p is in last file - if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { - return f - } - // p is not in last file - search all files - if i := searchFiles(s.files, int(p)); i >= 0 { - f := s.files[i] - // f.base <= int(p) by definition of searchFiles - if int(p) <= f.base+f.size { - s.last = f - return f - } - } - return nil -} - -// File returns the file that contains the position p. -// If no such file is found (for instance for p == NoPos), -// the result is nil. -// -func (s *FileSet) File(p Pos) (f *File) { - if p != NoPos { - s.mutex.RLock() - f = s.file(p) - s.mutex.RUnlock() - } - return -} - -// Position converts a Pos in the fileset into a general Position. -func (s *FileSet) Position(p Pos) (pos Position) { - if p != NoPos { - s.mutex.RLock() - if f := s.file(p); f != nil { - pos = f.position(p) - } - s.mutex.RUnlock() - } - return -} - -// ----------------------------------------------------------------------------- -// Helper functions - -func searchInts(a []int, x int) int { - // This function body is a manually inlined version of: - // - // return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 - // - // With better compiler optimizations, this may not be needed in the - // future, but at the moment this change improves the go/printer - // benchmark performance by ~30%. This has a direct impact on the - // speed of gofmt and thus seems worthwhile (2011-04-29). - // TODO(gri): Remove this when compilers have caught up. - i, j := 0, len(a) - for i < j { - h := i + (j-i)/2 // avoid overflow when computing h - // i ≤ h < j - if a[h] <= x { - i = h + 1 - } else { - j = h - } - } - return i - 1 -} diff --git a/vendor/gopkg.in/gcfg.v1/token/serialize.go b/vendor/gopkg.in/gcfg.v1/token/serialize.go deleted file mode 100644 index 4adc8f9e334..00000000000 --- a/vendor/gopkg.in/gcfg.v1/token/serialize.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package token - -type serializedFile struct { - // fields correspond 1:1 to fields with same (lower-case) name in File - Name string - Base int - Size int - Lines []int - Infos []lineInfo -} - -type serializedFileSet struct { - Base int - Files []serializedFile -} - -// Read calls decode to deserialize a file set into s; s must not be nil. -func (s *FileSet) Read(decode func(interface{}) error) error { - var ss serializedFileSet - if err := decode(&ss); err != nil { - return err - } - - s.mutex.Lock() - s.base = ss.Base - files := make([]*File, len(ss.Files)) - for i := 0; i < len(ss.Files); i++ { - f := &ss.Files[i] - files[i] = &File{s, f.Name, f.Base, f.Size, f.Lines, f.Infos} - } - s.files = files - s.last = nil - s.mutex.Unlock() - - return nil -} - -// Write calls encode to serialize the file set s. -func (s *FileSet) Write(encode func(interface{}) error) error { - var ss serializedFileSet - - s.mutex.Lock() - ss.Base = s.base - files := make([]serializedFile, len(s.files)) - for i, f := range s.files { - files[i] = serializedFile{f.name, f.base, f.size, f.lines, f.infos} - } - ss.Files = files - s.mutex.Unlock() - - return encode(ss) -} diff --git a/vendor/gopkg.in/gcfg.v1/token/token.go b/vendor/gopkg.in/gcfg.v1/token/token.go deleted file mode 100644 index b3c7c83fa9e..00000000000 --- a/vendor/gopkg.in/gcfg.v1/token/token.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package token defines constants representing the lexical tokens of the gcfg -// configuration syntax and basic operations on tokens (printing, predicates). -// -// Note that the API for the token package may change to accommodate new -// features or implementation changes in gcfg. -// -package token - -import "strconv" - -// Token is the set of lexical tokens of the gcfg configuration syntax. -type Token int - -// The list of tokens. -const ( - // Special tokens - ILLEGAL Token = iota - EOF - COMMENT - - literal_beg - // Identifiers and basic type literals - // (these tokens stand for classes of literals) - IDENT // section-name, variable-name - STRING // "subsection-name", variable value - literal_end - - operator_beg - // Operators and delimiters - ASSIGN // = - LBRACK // [ - RBRACK // ] - EOL // \n - operator_end -) - -var tokens = [...]string{ - ILLEGAL: "ILLEGAL", - - EOF: "EOF", - COMMENT: "COMMENT", - - IDENT: "IDENT", - STRING: "STRING", - - ASSIGN: "=", - LBRACK: "[", - RBRACK: "]", - EOL: "\n", -} - -// String returns the string corresponding to the token tok. -// For operators and delimiters, the string is the actual token character -// sequence (e.g., for the token ASSIGN, the string is "="). For all other -// tokens the string corresponds to the token constant name (e.g. for the -// token IDENT, the string is "IDENT"). -// -func (tok Token) String() string { - s := "" - if 0 <= tok && tok < Token(len(tokens)) { - s = tokens[tok] - } - if s == "" { - s = "token(" + strconv.Itoa(int(tok)) + ")" - } - return s -} - -// Predicates - -// IsLiteral returns true for tokens corresponding to identifiers -// and basic type literals; it returns false otherwise. -// -func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end } - -// IsOperator returns true for tokens corresponding to operators and -// delimiters; it returns false otherwise. -// -func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end } diff --git a/vendor/gopkg.in/gcfg.v1/types/bool.go b/vendor/gopkg.in/gcfg.v1/types/bool.go deleted file mode 100644 index 8dcae0d8cfd..00000000000 --- a/vendor/gopkg.in/gcfg.v1/types/bool.go +++ /dev/null @@ -1,23 +0,0 @@ -package types - -// BoolValues defines the name and value mappings for ParseBool. -var BoolValues = map[string]interface{}{ - "true": true, "yes": true, "on": true, "1": true, - "false": false, "no": false, "off": false, "0": false, -} - -var boolParser = func() *EnumParser { - ep := &EnumParser{} - ep.AddVals(BoolValues) - return ep -}() - -// ParseBool parses bool values according to the definitions in BoolValues. -// Parsing is case-insensitive. -func ParseBool(s string) (bool, error) { - v, err := boolParser.Parse(s) - if err != nil { - return false, err - } - return v.(bool), nil -} diff --git a/vendor/gopkg.in/gcfg.v1/types/doc.go b/vendor/gopkg.in/gcfg.v1/types/doc.go deleted file mode 100644 index 9f9c345f6ea..00000000000 --- a/vendor/gopkg.in/gcfg.v1/types/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package types defines helpers for type conversions. -// -// The API for this package is not finalized yet. -package types diff --git a/vendor/gopkg.in/gcfg.v1/types/enum.go b/vendor/gopkg.in/gcfg.v1/types/enum.go deleted file mode 100644 index 1a0c7ef453d..00000000000 --- a/vendor/gopkg.in/gcfg.v1/types/enum.go +++ /dev/null @@ -1,44 +0,0 @@ -package types - -import ( - "fmt" - "reflect" - "strings" -) - -// EnumParser parses "enum" values; i.e. a predefined set of strings to -// predefined values. -type EnumParser struct { - Type string // type name; if not set, use type of first value added - CaseMatch bool // if true, matching of strings is case-sensitive - // PrefixMatch bool - vals map[string]interface{} -} - -// AddVals adds strings and values to an EnumParser. -func (ep *EnumParser) AddVals(vals map[string]interface{}) { - if ep.vals == nil { - ep.vals = make(map[string]interface{}) - } - for k, v := range vals { - if ep.Type == "" { - ep.Type = reflect.TypeOf(v).Name() - } - if !ep.CaseMatch { - k = strings.ToLower(k) - } - ep.vals[k] = v - } -} - -// Parse parses the string and returns the value or an error. -func (ep EnumParser) Parse(s string) (interface{}, error) { - if !ep.CaseMatch { - s = strings.ToLower(s) - } - v, ok := ep.vals[s] - if !ok { - return false, fmt.Errorf("failed to parse %s %#q", ep.Type, s) - } - return v, nil -} diff --git a/vendor/gopkg.in/gcfg.v1/types/int.go b/vendor/gopkg.in/gcfg.v1/types/int.go deleted file mode 100644 index af7e75c1250..00000000000 --- a/vendor/gopkg.in/gcfg.v1/types/int.go +++ /dev/null @@ -1,86 +0,0 @@ -package types - -import ( - "fmt" - "strings" -) - -// An IntMode is a mode for parsing integer values, representing a set of -// accepted bases. -type IntMode uint8 - -// IntMode values for ParseInt; can be combined using binary or. -const ( - Dec IntMode = 1 << iota - Hex - Oct -) - -// String returns a string representation of IntMode; e.g. `IntMode(Dec|Hex)`. -func (m IntMode) String() string { - var modes []string - if m&Dec != 0 { - modes = append(modes, "Dec") - } - if m&Hex != 0 { - modes = append(modes, "Hex") - } - if m&Oct != 0 { - modes = append(modes, "Oct") - } - return "IntMode(" + strings.Join(modes, "|") + ")" -} - -var errIntAmbig = fmt.Errorf("ambiguous integer value; must include '0' prefix") - -func prefix0(val string) bool { - return strings.HasPrefix(val, "0") || strings.HasPrefix(val, "-0") -} - -func prefix0x(val string) bool { - return strings.HasPrefix(val, "0x") || strings.HasPrefix(val, "-0x") -} - -// ParseInt parses val using mode into intptr, which must be a pointer to an -// integer kind type. Non-decimal value require prefix `0` or `0x` in the cases -// when mode permits ambiguity of base; otherwise the prefix can be omitted. -func ParseInt(intptr interface{}, val string, mode IntMode) error { - val = strings.TrimSpace(val) - verb := byte(0) - switch mode { - case Dec: - verb = 'd' - case Dec + Hex: - if prefix0x(val) { - verb = 'v' - } else { - verb = 'd' - } - case Dec + Oct: - if prefix0(val) && !prefix0x(val) { - verb = 'v' - } else { - verb = 'd' - } - case Dec + Hex + Oct: - verb = 'v' - case Hex: - if prefix0x(val) { - verb = 'v' - } else { - verb = 'x' - } - case Oct: - verb = 'o' - case Hex + Oct: - if prefix0(val) { - verb = 'v' - } else { - return errIntAmbig - } - } - if verb == 0 { - panic("unsupported mode") - } - return ScanFully(intptr, val, verb) -} diff --git a/vendor/gopkg.in/gcfg.v1/types/scan.go b/vendor/gopkg.in/gcfg.v1/types/scan.go deleted file mode 100644 index db2f6ed3caf..00000000000 --- a/vendor/gopkg.in/gcfg.v1/types/scan.go +++ /dev/null @@ -1,23 +0,0 @@ -package types - -import ( - "fmt" - "io" - "reflect" -) - -// ScanFully uses fmt.Sscanf with verb to fully scan val into ptr. -func ScanFully(ptr interface{}, val string, verb byte) error { - t := reflect.ValueOf(ptr).Elem().Type() - // attempt to read extra bytes to make sure the value is consumed - var b []byte - n, err := fmt.Sscanf(val, "%"+string(verb)+"%s", ptr, &b) - switch { - case n < 1 || n == 1 && err != io.EOF: - return fmt.Errorf("failed to parse %q as %v: %v", val, t, err) - case n > 1: - return fmt.Errorf("failed to parse %q as %v: extra characters %q", val, t, string(b)) - } - // n == 1 && err == io.EOF - return nil -} diff --git a/vendor/gopkg.in/warnings.v0/LICENSE b/vendor/gopkg.in/warnings.v0/LICENSE deleted file mode 100644 index d65f7e9d8cd..00000000000 --- a/vendor/gopkg.in/warnings.v0/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2016 Péter Surányi. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/warnings.v0/README b/vendor/gopkg.in/warnings.v0/README deleted file mode 100644 index 974212ba1b9..00000000000 --- a/vendor/gopkg.in/warnings.v0/README +++ /dev/null @@ -1,77 +0,0 @@ -Package warnings implements error handling with non-fatal errors (warnings). - -import path: "gopkg.in/warnings.v0" -package docs: https://godoc.org/gopkg.in/warnings.v0 -issues: https://github.com/go-warnings/warnings/issues -pull requests: https://github.com/go-warnings/warnings/pulls - -A recurring pattern in Go programming is the following: - - func myfunc(params) error { - if err := doSomething(...); err != nil { - return err - } - if err := doSomethingElse(...); err != nil { - return err - } - if ok := doAnotherThing(...); !ok { - return errors.New("my error") - } - ... - return nil - } - -This pattern allows interrupting the flow on any received error. But what if -there are errors that should be noted but still not fatal, for which the flow -should not be interrupted? Implementing such logic at each if statement would -make the code complex and the flow much harder to follow. - -Package warnings provides the Collector type and a clean and simple pattern -for achieving such logic. The Collector takes care of deciding when to break -the flow and when to continue, collecting any non-fatal errors (warnings) -along the way. The only requirement is that fatal and non-fatal errors can be -distinguished programmatically; that is a function such as - - IsFatal(error) bool - -must be implemented. The following is an example of what the above snippet -could look like using the warnings package: - - import "gopkg.in/warnings.v0" - - func isFatal(err error) bool { - _, ok := err.(WarningType) - return !ok - } - - func myfunc(params) error { - c := warnings.NewCollector(isFatal) - c.FatalWithWarnings = true - if err := c.Collect(doSomething()); err != nil { - return err - } - if err := c.Collect(doSomethingElse(...)); err != nil { - return err - } - if ok := doAnotherThing(...); !ok { - if err := c.Collect(errors.New("my error")); err != nil { - return err - } - } - ... - return c.Done() - } - -For an example of a non-trivial code base using this library, see -gopkg.in/gcfg.v1 - -Rules for using warnings - - - ensure that warnings are programmatically distinguishable from fatal - errors (i.e. implement an isFatal function and any necessary error types) - - ensure that there is a single Collector instance for a call of each - exported function - - ensure that all errors (fatal or warning) are fed through Collect - - ensure that every time an error is returned, it is one returned by a - Collector (from Collect or Done) - - ensure that Collect is never called after Done diff --git a/vendor/gopkg.in/warnings.v0/warnings.go b/vendor/gopkg.in/warnings.v0/warnings.go deleted file mode 100644 index b849d1e3d9a..00000000000 --- a/vendor/gopkg.in/warnings.v0/warnings.go +++ /dev/null @@ -1,194 +0,0 @@ -// Package warnings implements error handling with non-fatal errors (warnings). -// -// A recurring pattern in Go programming is the following: -// -// func myfunc(params) error { -// if err := doSomething(...); err != nil { -// return err -// } -// if err := doSomethingElse(...); err != nil { -// return err -// } -// if ok := doAnotherThing(...); !ok { -// return errors.New("my error") -// } -// ... -// return nil -// } -// -// This pattern allows interrupting the flow on any received error. But what if -// there are errors that should be noted but still not fatal, for which the flow -// should not be interrupted? Implementing such logic at each if statement would -// make the code complex and the flow much harder to follow. -// -// Package warnings provides the Collector type and a clean and simple pattern -// for achieving such logic. The Collector takes care of deciding when to break -// the flow and when to continue, collecting any non-fatal errors (warnings) -// along the way. The only requirement is that fatal and non-fatal errors can be -// distinguished programmatically; that is a function such as -// -// IsFatal(error) bool -// -// must be implemented. The following is an example of what the above snippet -// could look like using the warnings package: -// -// import "gopkg.in/warnings.v0" -// -// func isFatal(err error) bool { -// _, ok := err.(WarningType) -// return !ok -// } -// -// func myfunc(params) error { -// c := warnings.NewCollector(isFatal) -// c.FatalWithWarnings = true -// if err := c.Collect(doSomething()); err != nil { -// return err -// } -// if err := c.Collect(doSomethingElse(...)); err != nil { -// return err -// } -// if ok := doAnotherThing(...); !ok { -// if err := c.Collect(errors.New("my error")); err != nil { -// return err -// } -// } -// ... -// return c.Done() -// } -// -// For an example of a non-trivial code base using this library, see -// gopkg.in/gcfg.v1 -// -// Rules for using warnings -// -// - ensure that warnings are programmatically distinguishable from fatal -// errors (i.e. implement an isFatal function and any necessary error types) -// - ensure that there is a single Collector instance for a call of each -// exported function -// - ensure that all errors (fatal or warning) are fed through Collect -// - ensure that every time an error is returned, it is one returned by a -// Collector (from Collect or Done) -// - ensure that Collect is never called after Done -// -// TODO -// -// - optionally limit the number of warnings (e.g. stop after 20 warnings) (?) -// - consider interaction with contexts -// - go vet-style invocations verifier -// - semi-automatic code converter -// -package warnings // import "gopkg.in/warnings.v0" - -import ( - "bytes" - "fmt" -) - -// List holds a collection of warnings and optionally one fatal error. -type List struct { - Warnings []error - Fatal error -} - -// Error implements the error interface. -func (l List) Error() string { - b := bytes.NewBuffer(nil) - if l.Fatal != nil { - fmt.Fprintln(b, "fatal:") - fmt.Fprintln(b, l.Fatal) - } - switch len(l.Warnings) { - case 0: - // nop - case 1: - fmt.Fprintln(b, "warning:") - default: - fmt.Fprintln(b, "warnings:") - } - for _, err := range l.Warnings { - fmt.Fprintln(b, err) - } - return b.String() -} - -// A Collector collects errors up to the first fatal error. -type Collector struct { - // IsFatal distinguishes between warnings and fatal errors. - IsFatal func(error) bool - // FatalWithWarnings set to true means that a fatal error is returned as - // a List together with all warnings so far. The default behavior is to - // only return the fatal error and discard any warnings that have been - // collected. - FatalWithWarnings bool - - l List - done bool -} - -// NewCollector returns a new Collector; it uses isFatal to distinguish between -// warnings and fatal errors. -func NewCollector(isFatal func(error) bool) *Collector { - return &Collector{IsFatal: isFatal} -} - -// Collect collects a single error (warning or fatal). It returns nil if -// collection can continue (only warnings so far), or otherwise the errors -// collected. Collect mustn't be called after the first fatal error or after -// Done has been called. -func (c *Collector) Collect(err error) error { - if c.done { - panic("warnings.Collector already done") - } - if err == nil { - return nil - } - if c.IsFatal(err) { - c.done = true - c.l.Fatal = err - } else { - c.l.Warnings = append(c.l.Warnings, err) - } - if c.l.Fatal != nil { - return c.erorr() - } - return nil -} - -// Done ends collection and returns the collected error(s). -func (c *Collector) Done() error { - c.done = true - return c.erorr() -} - -func (c *Collector) erorr() error { - if !c.FatalWithWarnings && c.l.Fatal != nil { - return c.l.Fatal - } - if c.l.Fatal == nil && len(c.l.Warnings) == 0 { - return nil - } - // Note that a single warning is also returned as a List. This is to make it - // easier to determine fatal-ness of the returned error. - return c.l -} - -// FatalOnly returns the fatal error, if any, **in an error returned by a -// Collector**. It returns nil if and only if err is nil or err is a List -// with err.Fatal == nil. -func FatalOnly(err error) error { - l, ok := err.(List) - if !ok { - return err - } - return l.Fatal -} - -// WarningsOnly returns the warnings **in an error returned by a Collector**. -func WarningsOnly(err error) []error { - l, ok := err.(List) - if !ok { - return nil - } - return l.Warnings -} diff --git a/vendor/k8s.io/cloud-provider-vsphere/LICENSE b/vendor/k8s.io/cloud-provider-vsphere/LICENSE deleted file mode 100644 index d6456956733..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config.go deleted file mode 100644 index 5aaa9a82b18..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config.go +++ /dev/null @@ -1,285 +0,0 @@ -/* -Copyright 2018 The Kubernetes 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 config - -import ( - "fmt" - "os" - "strconv" - "strings" - - klog "k8s.io/klog/v2" -) - -/* - TODO: - When the INI based cloud-config is deprecated, this functions below should be preserved -*/ - -func getEnvKeyValue(match string, partial bool) (string, string, error) { - for _, e := range os.Environ() { - pair := strings.Split(e, "=") - if len(pair) != 2 { - continue - } - - key := pair[0] - value := pair[1] - - if partial && strings.Contains(key, match) { - return key, value, nil - } - - if strings.Compare(key, match) == 0 { - return key, value, nil - } - } - - matchType := "match" - if partial { - matchType = "partial match" - } - - return "", "", fmt.Errorf("Failed to find %s with %s", matchType, match) -} - -// FromEnv initializes the provided configuratoin object with values -// obtained from environment variables. If an environment variable is set -// for a property that's already initialized, the environment variable's value -// takes precedence. -func (cfg *Config) FromEnv() error { - - //Init - if cfg.VirtualCenter == nil { - cfg.VirtualCenter = make(map[string]*VirtualCenterConfig) - } - - //Globals - if v := os.Getenv("VSPHERE_VCENTER"); v != "" { - cfg.Global.VCenterIP = v - } - if v := os.Getenv("VSPHERE_VCENTER_PORT"); v != "" { - cfg.Global.VCenterPort = v - } - if v := os.Getenv("VSPHERE_USER"); v != "" { - cfg.Global.User = v - } - if v := os.Getenv("VSPHERE_PASSWORD"); v != "" { - cfg.Global.Password = v - } - if v := os.Getenv("VSPHERE_DATACENTER"); v != "" { - cfg.Global.Datacenters = v - } - if v := os.Getenv("VSPHERE_SECRET_NAME"); v != "" { - cfg.Global.SecretName = v - } - if v := os.Getenv("VSPHERE_SECRET_NAMESPACE"); v != "" { - cfg.Global.SecretNamespace = v - } - - if v := os.Getenv("VSPHERE_ROUNDTRIP_COUNT"); v != "" { - tmp, err := strconv.ParseUint(v, 10, 32) - if err != nil { - klog.Errorf("Failed to parse VSPHERE_ROUNDTRIP_COUNT: %s", err) - } else { - cfg.Global.RoundTripperCount = uint(tmp) - } - } - - if v := os.Getenv("VSPHERE_INSECURE"); v != "" { - InsecureFlag, err := strconv.ParseBool(v) - if err != nil { - klog.Errorf("Failed to parse VSPHERE_INSECURE: %s", err) - } else { - cfg.Global.InsecureFlag = InsecureFlag - } - } - - if v := os.Getenv("VSPHERE_SECRETS_DIRECTORY"); v != "" { - cfg.Global.SecretsDirectory = v - } - if cfg.Global.SecretsDirectory == "" { - cfg.Global.SecretsDirectory = DefaultSecretDirectory - } - if _, err := os.Stat(cfg.Global.SecretsDirectory); os.IsNotExist(err) { - cfg.Global.SecretsDirectory = "" //Dir does not exist, set to empty string - } - - if v := os.Getenv("VSPHERE_CAFILE"); v != "" { - cfg.Global.CAFile = v - } - if v := os.Getenv("VSPHERE_THUMBPRINT"); v != "" { - cfg.Global.Thumbprint = v - } - if v := os.Getenv("VSPHERE_LABEL_REGION"); v != "" { - cfg.Labels.Region = v - } - if v := os.Getenv("VSPHERE_LABEL_ZONE"); v != "" { - cfg.Labels.Zone = v - } - - //Build VirtualCenter from ENVs - for _, e := range os.Environ() { - pair := strings.Split(e, "=") - - if len(pair) != 2 { - continue - } - - key := pair[0] - value := pair[1] - - if strings.HasPrefix(key, "VSPHERE_VCENTER_") && len(value) > 0 { - id := strings.TrimPrefix(key, "VSPHERE_VCENTER_") - vcenter := value - - _, username, errUsername := getEnvKeyValue("VCENTER_"+id+"_USERNAME", false) - if errUsername != nil { - username = cfg.Global.User - } - _, password, errPassword := getEnvKeyValue("VCENTER_"+id+"_PASSWORD", false) - if errPassword != nil { - password = cfg.Global.Password - } - _, server, errServer := getEnvKeyValue("VCENTER_"+id+"_SERVER", false) - if errServer != nil { - server = "" - } - _, port, errPort := getEnvKeyValue("VCENTER_"+id+"_PORT", false) - if errPort != nil { - port = cfg.Global.VCenterPort - } - insecureFlag := false - _, insecureTmp, errInsecure := getEnvKeyValue("VCENTER_"+id+"_INSECURE", false) - if errInsecure != nil { - insecureFlagTmp, errTmp := strconv.ParseBool(insecureTmp) - if errTmp == nil { - insecureFlag = insecureFlagTmp - } - } - _, datacenters, errDatacenters := getEnvKeyValue("VCENTER_"+id+"_DATACENTERS", false) - if errDatacenters != nil { - datacenters = cfg.Global.Datacenters - } - roundtrip := DefaultRoundTripperCount - _, roundtripTmp, errRoundtrip := getEnvKeyValue("VCENTER_"+id+"_ROUNDTRIP", false) - if errRoundtrip != nil { - roundtripFlagTmp, errTmp := strconv.ParseUint(roundtripTmp, 10, 32) - if errTmp == nil { - roundtrip = uint(roundtripFlagTmp) - } - } - _, caFile, errCaFile := getEnvKeyValue("VCENTER_"+id+"_CAFILE", false) - if errCaFile != nil { - caFile = cfg.Global.CAFile - } - _, thumbprint, errThumbprint := getEnvKeyValue("VCENTER_"+id+"_THUMBPRINT", false) - if errThumbprint != nil { - thumbprint = cfg.Global.Thumbprint - } - - _, secretName, secretNameErr := getEnvKeyValue("VCENTER_"+id+"_SECRET_NAME", false) - _, secretNamespace, secretNamespaceErr := getEnvKeyValue("VCENTER_"+id+"_SECRET_NAMESPACE", false) - - if secretNameErr != nil || secretNamespaceErr != nil { - secretName = "" - secretNamespace = "" - } - secretRef := DefaultCredentialManager - if secretName != "" && secretNamespace != "" { - secretRef = vcenter - } - - iPFamilyPriority := []string{DefaultIPFamily} - _, ipFamily, errIPFamily := getEnvKeyValue("VCENTER_"+id+"_IP_FAMILY", false) - if errIPFamily != nil { - iPFamilyPriority = []string{ipFamily} - } - - // If server is explicitly set, that means the vcenter value above is the TenantRef - vcenterIP := vcenter - tenantRef := vcenter - if server != "" { - vcenterIP = server - tenantRef = vcenter - } - - var vcc *VirtualCenterConfig - if cfg.VirtualCenter[tenantRef] != nil { - vcc = cfg.VirtualCenter[tenantRef] - } else { - vcc = &VirtualCenterConfig{} - cfg.VirtualCenter[tenantRef] = vcc - } - - vcc.User = username - vcc.Password = password - vcc.TenantRef = tenantRef - vcc.VCenterIP = vcenterIP - vcc.VCenterPort = port - vcc.InsecureFlag = insecureFlag - vcc.Datacenters = datacenters - vcc.RoundTripperCount = roundtrip - vcc.CAFile = caFile - vcc.Thumbprint = thumbprint - vcc.SecretRef = secretRef - vcc.SecretName = secretName - vcc.SecretNamespace = secretNamespace - vcc.IPFamilyPriority = iPFamilyPriority - } - } - - return nil -} - -/* - TODO: - When the INI based cloud-config is deprecated, the references to the - INI based code (ie the call to ReadConfigINI) below should be deleted. -*/ - -// ReadConfig parses vSphere cloud config file and stores it into VSphereConfig. -// Environment variables are also checked -func ReadConfig(byConfig []byte) (*Config, error) { - if len(byConfig) == 0 { - return nil, fmt.Errorf("Invalid YAML/INI file") - } - - cfg, err := ReadConfigYAML(byConfig) - if err != nil { - klog.Warningf("ReadConfigYAML failed: %s", err) - - cfg, err = ReadConfigINI(byConfig) - if err != nil { - klog.Errorf("ReadConfigINI failed: %s", err) - return nil, err - } - - klog.Info("ReadConfig INI succeeded. INI-based cloud-config is deprecated and will be removed in 2.0. Please use YAML based cloud-config.") - } else { - klog.Info("ReadConfig YAML succeeded") - } - - // Env Vars should override config file entries if present - if err := cfg.FromEnv(); err != nil { - klog.Errorf("FromEnv failed: %s", err) - return nil, err - } - - klog.Info("Config initialized") - return cfg, nil -} diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config_ini_legacy.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config_ini_legacy.go deleted file mode 100644 index 049707a12b1..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config_ini_legacy.go +++ /dev/null @@ -1,265 +0,0 @@ -/* -Copyright 2020 The Kubernetes 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 config - -import ( - "fmt" - "strings" - - ini "gopkg.in/gcfg.v1" - klog "k8s.io/klog/v2" -) - -/* - TODO: - When the INI based cloud-config is deprecated. This file should be deleted. -*/ - -// CreateConfig generates a common Config object based on what other structs and funcs -// are already dependent upon in other packages. -func (cci *CommonConfigINI) CreateConfig() *Config { - cfg := &Config{ - VirtualCenter: make(map[string]*VirtualCenterConfig), - } - - cfg.Global.User = cci.Global.User - cfg.Global.Password = cci.Global.Password - cfg.Global.VCenterIP = cci.Global.VCenterIP - cfg.Global.VCenterPort = cci.Global.VCenterPort - cfg.Global.InsecureFlag = cci.Global.InsecureFlag - cfg.Global.Datacenters = cci.Global.Datacenters - cfg.Global.RoundTripperCount = cci.Global.RoundTripperCount - cfg.Global.CAFile = cci.Global.CAFile - cfg.Global.Thumbprint = cci.Global.Thumbprint - cfg.Global.SecretName = cci.Global.SecretName - cfg.Global.SecretNamespace = cci.Global.SecretNamespace - cfg.Global.SecretsDirectory = cci.Global.SecretsDirectory - - for keyVcConfig, valVcConfig := range cci.VirtualCenter { - cfg.VirtualCenter[keyVcConfig] = &VirtualCenterConfig{ - User: valVcConfig.User, - Password: valVcConfig.Password, - TenantRef: valVcConfig.TenantRef, - VCenterIP: valVcConfig.VCenterIP, - VCenterPort: valVcConfig.VCenterPort, - InsecureFlag: valVcConfig.InsecureFlag, - Datacenters: valVcConfig.Datacenters, - RoundTripperCount: valVcConfig.RoundTripperCount, - CAFile: valVcConfig.CAFile, - Thumbprint: valVcConfig.Thumbprint, - SecretRef: valVcConfig.SecretRef, - SecretName: valVcConfig.SecretName, - SecretNamespace: valVcConfig.SecretNamespace, - IPFamilyPriority: valVcConfig.IPFamilyPriority, - } - } - - cfg.Labels.Region = cci.Labels.Region - cfg.Labels.Zone = cci.Labels.Zone - - return cfg -} - -// validateIPFamily takes the possible values of IPFamily and initializes the -// slice as determined bby priority -func (vcci *VirtualCenterConfigINI) validateIPFamily() error { - if len(vcci.IPFamily) == 0 { - vcci.IPFamily = DefaultIPFamily - } - - ipFamilies := strings.Split(vcci.IPFamily, ",") - for i, ipFamily := range ipFamilies { - ipFamily = strings.TrimSpace(ipFamily) - if len(ipFamily) == 0 { - copy(ipFamilies[i:], ipFamilies[i+1:]) // Shift a[i+1:] left one index. - ipFamilies[len(ipFamilies)-1] = "" // Erase last element (write zero value). - ipFamilies = ipFamilies[:len(ipFamilies)-1] // Truncate slice. - continue - } - if !strings.EqualFold(ipFamily, IPv4Family) && !strings.EqualFold(ipFamily, IPv6Family) { - return ErrInvalidIPFamilyType - } - } - - vcci.IPFamilyPriority = ipFamilies - return nil -} - -// isSecretInfoProvided returns true if k8s secret is set or using generic CO secret method. -// If both k8s secret and generic CO both are true, we don't know which to use, so return false. -func (cci *CommonConfigINI) isSecretInfoProvided() bool { - return (cci.Global.SecretName != "" && cci.Global.SecretNamespace != "" && cci.Global.SecretsDirectory == "") || - (cci.Global.SecretName == "" && cci.Global.SecretNamespace == "" && cci.Global.SecretsDirectory != "") -} - -// isSecretInfoProvided returns true if the secret per VC has been configured -func (vcci *VirtualCenterConfigINI) isSecretInfoProvided() bool { - return vcci.SecretName != "" && vcci.SecretNamespace != "" -} - -func (cci *CommonConfigINI) validateConfig() error { - //Fix default global values - if cci.Global.RoundTripperCount == 0 { - cci.Global.RoundTripperCount = DefaultRoundTripperCount - } - if cci.Global.VCenterPort == "" { - cci.Global.VCenterPort = DefaultVCenterPortStr - } - if cci.Global.APIBinding == "" { - cci.Global.APIBinding = DefaultAPIBinding - } - if cci.Global.IPFamily == "" { - cci.Global.IPFamily = DefaultIPFamily - } - - // Create a single instance of VSphereInstance for the Global VCenterIP if the - // VirtualCenter does not already exist in the map - if cci.Global.VCenterIP != "" && cci.VirtualCenter[cci.Global.VCenterIP] == nil { - cci.VirtualCenter[cci.Global.VCenterIP] = &VirtualCenterConfigINI{ - User: cci.Global.User, - Password: cci.Global.Password, - TenantRef: cci.Global.VCenterIP, - VCenterIP: cci.Global.VCenterIP, - VCenterPort: cci.Global.VCenterPort, - InsecureFlag: cci.Global.InsecureFlag, - Datacenters: cci.Global.Datacenters, - RoundTripperCount: cci.Global.RoundTripperCount, - CAFile: cci.Global.CAFile, - Thumbprint: cci.Global.Thumbprint, - SecretRef: DefaultCredentialManager, - SecretName: cci.Global.SecretName, - SecretNamespace: cci.Global.SecretNamespace, - IPFamily: cci.Global.IPFamily, - } - } - - // Must have at least one vCenter defined - if len(cci.VirtualCenter) == 0 { - klog.Error(ErrMissingVCenter) - return ErrMissingVCenter - } - - // vsphere.conf is no longer supported in the old format. - for vcServer, vcConfig := range cci.VirtualCenter { - klog.V(4).Infof("Initializing vc server %s", vcServer) - if vcServer == "" { - klog.Error(ErrInvalidVCenterIP) - return ErrInvalidVCenterIP - } - - // If vcConfig.VCenterIP is explicitly set, that means the vcServer - // above is the TenantRef - if vcConfig.VCenterIP != "" { - //vcConfig.VCenterIP is already set - vcConfig.TenantRef = vcServer - } else { - vcConfig.VCenterIP = vcServer - vcConfig.TenantRef = vcServer - } - - if !cci.isSecretInfoProvided() && !vcConfig.isSecretInfoProvided() { - if vcConfig.User == "" { - vcConfig.User = cci.Global.User - if vcConfig.User == "" { - klog.Errorf("vcConfig.User is empty for vc %s!", vcServer) - return ErrUsernameMissing - } - } - if vcConfig.Password == "" { - vcConfig.Password = cci.Global.Password - if vcConfig.Password == "" { - klog.Errorf("vcConfig.Password is empty for vc %s!", vcServer) - return ErrPasswordMissing - } - } - } else if cci.isSecretInfoProvided() && !vcConfig.isSecretInfoProvided() { - vcConfig.SecretRef = DefaultCredentialManager - } else if vcConfig.isSecretInfoProvided() { - vcConfig.SecretRef = vcConfig.SecretNamespace + "/" + vcConfig.SecretName - } - - if vcConfig.VCenterPort == "" { - vcConfig.VCenterPort = cci.Global.VCenterPort - } - - if vcConfig.Datacenters == "" { - if cci.Global.Datacenters != "" { - vcConfig.Datacenters = cci.Global.Datacenters - } - } - if vcConfig.RoundTripperCount == 0 { - vcConfig.RoundTripperCount = cci.Global.RoundTripperCount - } - if vcConfig.CAFile == "" { - vcConfig.CAFile = cci.Global.CAFile - } - if vcConfig.Thumbprint == "" { - vcConfig.Thumbprint = cci.Global.Thumbprint - } - - if vcConfig.IPFamily == "" { - vcConfig.IPFamily = cci.Global.IPFamily - } - - err := vcConfig.validateIPFamily() - if err != nil { - klog.Errorf("Invalid vcConfig IPFamily: %s, err=%s", vcConfig.IPFamily, err) - return err - } - - insecure := vcConfig.InsecureFlag - if !insecure { - vcConfig.InsecureFlag = cci.Global.InsecureFlag - } - } - - return nil -} - -// ReadRawConfigINI parses vSphere cloud config file and stores it into ConfigINI -func ReadRawConfigINI(byConfig []byte) (*CommonConfigINI, error) { - if len(byConfig) == 0 { - return nil, fmt.Errorf("Invalid INI file") - } - - strConfig := string(byConfig[:]) - - cfg := &CommonConfigINI{ - VirtualCenter: make(map[string]*VirtualCenterConfigINI), - } - - if err := ini.FatalOnly(ini.ReadStringInto(cfg, strConfig)); err != nil { - return nil, err - } - - err := cfg.validateConfig() - if err != nil { - return nil, err - } - - return cfg, nil -} - -// ReadConfigINI parses vSphere cloud config file and stores it into Config -func ReadConfigINI(byConfig []byte) (*Config, error) { - cfg, err := ReadRawConfigINI(byConfig) - if err != nil { - return nil, err - } - - return cfg.CreateConfig(), nil -} diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config_yaml.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config_yaml.go deleted file mode 100644 index 56a67b3e114..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/config_yaml.go +++ /dev/null @@ -1,229 +0,0 @@ -/* -Copyright 2020 The Kubernetes 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 config - -import ( - "fmt" - "strings" - - yaml "gopkg.in/yaml.v2" - klog "k8s.io/klog/v2" -) - -/* - TODO: - When the INI based cloud-config is deprecated, this file should be merged into config.go - and this file should be deleted. -*/ - -// CreateConfig generates a common Config object based on what other structs and funcs -// are already dependent upon in other packages. -func (ccy *CommonConfigYAML) CreateConfig() *Config { - cfg := &Config{ - VirtualCenter: make(map[string]*VirtualCenterConfig), - } - - cfg.Global.User = ccy.Global.User - cfg.Global.Password = ccy.Global.Password - cfg.Global.VCenterIP = ccy.Global.VCenterIP - cfg.Global.VCenterPort = fmt.Sprint(ccy.Global.VCenterPort) - cfg.Global.InsecureFlag = ccy.Global.InsecureFlag - cfg.Global.Datacenters = strings.Join(ccy.Global.Datacenters, ",") - cfg.Global.RoundTripperCount = ccy.Global.RoundTripperCount - cfg.Global.CAFile = ccy.Global.CAFile - cfg.Global.Thumbprint = ccy.Global.Thumbprint - cfg.Global.SecretName = ccy.Global.SecretName - cfg.Global.SecretNamespace = ccy.Global.SecretNamespace - cfg.Global.SecretsDirectory = ccy.Global.SecretsDirectory - - for keyVcConfig, valVcConfig := range ccy.Vcenter { - cfg.VirtualCenter[keyVcConfig] = &VirtualCenterConfig{ - User: valVcConfig.User, - Password: valVcConfig.Password, - TenantRef: valVcConfig.TenantRef, - VCenterIP: valVcConfig.VCenterIP, - VCenterPort: fmt.Sprint(valVcConfig.VCenterPort), - InsecureFlag: valVcConfig.InsecureFlag, - Datacenters: strings.Join(valVcConfig.Datacenters, ","), - RoundTripperCount: valVcConfig.RoundTripperCount, - CAFile: valVcConfig.CAFile, - Thumbprint: valVcConfig.Thumbprint, - SecretRef: valVcConfig.SecretRef, - SecretName: valVcConfig.SecretName, - SecretNamespace: valVcConfig.SecretNamespace, - IPFamilyPriority: valVcConfig.IPFamilyPriority, - } - } - - cfg.Labels.Region = ccy.Labels.Region - cfg.Labels.Zone = ccy.Labels.Zone - - return cfg -} - -// isSecretInfoProvided returns true if k8s secret is set or using generic CO secret method. -// If both k8s secret and generic CO both are true, we don't know which to use, so return false. -func (ccy *CommonConfigYAML) isSecretInfoProvided() bool { - return (ccy.Global.SecretName != "" && ccy.Global.SecretNamespace != "" && ccy.Global.SecretsDirectory == "") || - (ccy.Global.SecretName == "" && ccy.Global.SecretNamespace == "" && ccy.Global.SecretsDirectory != "") -} - -// isSecretInfoProvided returns true if the secret per VC has been configured -func (vccy *VirtualCenterConfigYAML) isSecretInfoProvided() bool { - return vccy.SecretName != "" && vccy.SecretNamespace != "" -} - -func (ccy *CommonConfigYAML) validateConfig() error { - //Fix default global values - if ccy.Global.RoundTripperCount == 0 { - ccy.Global.RoundTripperCount = DefaultRoundTripperCount - } - if ccy.Global.VCenterPort == 0 { - ccy.Global.VCenterPort = DefaultVCenterPort - } - if ccy.Global.APIBinding == "" { - ccy.Global.APIBinding = DefaultAPIBinding - } - if len(ccy.Global.IPFamilyPriority) == 0 { - ccy.Global.IPFamilyPriority = []string{DefaultIPFamily} - } - - // Create a single instance of VSphereInstance for the Global VCenterIP if the - // VirtualCenter does not already exist in the map - if ccy.Global.VCenterIP != "" && ccy.Vcenter[ccy.Global.VCenterIP] == nil { - ccy.Vcenter[ccy.Global.VCenterIP] = &VirtualCenterConfigYAML{ - User: ccy.Global.User, - Password: ccy.Global.Password, - TenantRef: ccy.Global.VCenterIP, - VCenterIP: ccy.Global.VCenterIP, - VCenterPort: ccy.Global.VCenterPort, - InsecureFlag: ccy.Global.InsecureFlag, - Datacenters: ccy.Global.Datacenters, - RoundTripperCount: ccy.Global.RoundTripperCount, - CAFile: ccy.Global.CAFile, - Thumbprint: ccy.Global.Thumbprint, - SecretRef: DefaultCredentialManager, - SecretName: ccy.Global.SecretName, - SecretNamespace: ccy.Global.SecretNamespace, - IPFamilyPriority: ccy.Global.IPFamilyPriority, - } - } - - // Must have at least one vCenter defined - if len(ccy.Vcenter) == 0 { - klog.Error(ErrMissingVCenter) - return ErrMissingVCenter - } - - // vsphere.conf is no longer supported in the old format. - for tenantRef, vcConfig := range ccy.Vcenter { - klog.V(4).Infof("Initializing vc server %s", tenantRef) - if vcConfig.VCenterIP == "" { - klog.Error(ErrInvalidVCenterIP) - return ErrInvalidVCenterIP - } - - // in the YAML-based config, the tenant ref is required in the config - vcConfig.TenantRef = tenantRef - - if !ccy.isSecretInfoProvided() && !vcConfig.isSecretInfoProvided() { - if vcConfig.User == "" { - vcConfig.User = ccy.Global.User - if vcConfig.User == "" { - klog.Errorf("vcConfig.User is empty for vc %s!", tenantRef) - return ErrUsernameMissing - } - } - if vcConfig.Password == "" { - vcConfig.Password = ccy.Global.Password - if vcConfig.Password == "" { - klog.Errorf("vcConfig.Password is empty for vc %s!", tenantRef) - return ErrPasswordMissing - } - } - } else if ccy.isSecretInfoProvided() && !vcConfig.isSecretInfoProvided() { - vcConfig.SecretRef = DefaultCredentialManager - } else if vcConfig.isSecretInfoProvided() { - vcConfig.SecretRef = vcConfig.SecretNamespace + "/" + vcConfig.SecretName - } - - if vcConfig.VCenterPort == 0 { - vcConfig.VCenterPort = ccy.Global.VCenterPort - } - - if len(vcConfig.Datacenters) == 0 { - if len(ccy.Global.Datacenters) != 0 { - vcConfig.Datacenters = ccy.Global.Datacenters - } - } - if vcConfig.RoundTripperCount == 0 { - vcConfig.RoundTripperCount = ccy.Global.RoundTripperCount - } - if vcConfig.CAFile == "" { - vcConfig.CAFile = ccy.Global.CAFile - } - if vcConfig.Thumbprint == "" { - vcConfig.Thumbprint = ccy.Global.Thumbprint - } - - if len(vcConfig.IPFamilyPriority) == 0 { - vcConfig.IPFamilyPriority = ccy.Global.IPFamilyPriority - } - - insecure := vcConfig.InsecureFlag - if !insecure { - vcConfig.InsecureFlag = ccy.Global.InsecureFlag - } - } - - return nil -} - -// ReadRawConfigYAML parses vSphere cloud config file and stores it into ConfigYAML -func ReadRawConfigYAML(byConfig []byte) (*CommonConfigYAML, error) { - if len(byConfig) == 0 { - klog.Errorf("Invalid YAML file") - return nil, fmt.Errorf("Invalid YAML file") - } - - cfg := CommonConfigYAML{ - Vcenter: make(map[string]*VirtualCenterConfigYAML), - } - - if err := yaml.Unmarshal(byConfig, &cfg); err != nil { - klog.Errorf("Unmarshal failed: %s", err) - return nil, err - } - - err := cfg.validateConfig() - if err != nil { - klog.Errorf("validateConfig failed: %s", err) - return nil, err - } - - return &cfg, nil -} - -// ReadConfigYAML parses vSphere cloud config file and stores it into Config -func ReadConfigYAML(byConfig []byte) (*Config, error) { - cfg, err := ReadRawConfigYAML(byConfig) - if err != nil { - return nil, err - } - - return cfg.CreateConfig(), nil -} diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/consts_and_errors.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/consts_and_errors.go deleted file mode 100644 index 0ed200ffb6a..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/consts_and_errors.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2019 The Kubernetes 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 config - -import ( - "errors" -) - -const ( - // DefaultRoundTripperCount is the number of allowed round trips - // before an error is returned. - DefaultRoundTripperCount uint = 3 - - // DefaultAPIBinding is the default ADDRESS:PORT binding used for - // exposing the API service. - DefaultAPIBinding string = ":43001" - - // DefaultVCenterPortStr is the default port used to access vCenter in string form - DefaultVCenterPortStr string = "443" - // DefaultVCenterPort is the default port used to access vCenter in uint form - DefaultVCenterPort uint = 443 - - // DefaultSecretDirectory is the default path to the secrets directory. - DefaultSecretDirectory string = "/etc/cloud/secrets" - - // IPv6Family string representation for IPv6 - IPv6Family = "ipv6" - // IPv4Family string representation for IPv4 - IPv4Family = "ipv4" - - // DefaultIPFamily is the default IP addressing to use for networking - DefaultIPFamily = IPv4Family - - // DefaultCredentialManager used for the Global CredMgr/Lister - DefaultCredentialManager string = "Global" -) - -var ( - // ErrUsernameMissing is returned when the provided username is empty. - ErrUsernameMissing = errors.New("Username is missing") - - // ErrPasswordMissing is returned when the provided password is empty. - ErrPasswordMissing = errors.New("Password is missing") - - // ErrInvalidVCenterIP is returned when the provided vCenter IP address is - // missing from the provided configuration. - ErrInvalidVCenterIP = errors.New("vsphere.conf does not have the VirtualCenter IP address specified") - - // ErrMissingVCenter is returned when the provided configuration does not - // define any vCenters. - ErrMissingVCenter = errors.New("No Virtual Center hosts defined") - - // ErrInvalidIPFamilyType is returned when an invalid IPFamily type is encountered - ErrInvalidIPFamilyType = errors.New("Invalid IP Family type") -) diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_common.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_common.go deleted file mode 100644 index 493f2d4dba0..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_common.go +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright 2020 The Kubernetes 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 config - -/* - TODO: - When the INI based cloud-config is deprecated. This file should be deleted and - the structs in types_yaml.go will be renamed to replace the ones in this file. -*/ - -// Global struct -type Global struct { - // vCenter username. - User string - // vCenter password in clear text. - Password string - // Deprecated. Use VirtualCenter to specify multiple vCenter Servers. - // vCenter IP. - VCenterIP string - // vCenter port. - VCenterPort string - // True if vCenter uses self-signed cert. - InsecureFlag bool - // Datacenter in which VMs are located. - Datacenters string - // Soap round tripper count (retries = RoundTripper - 1) - RoundTripperCount uint - // Specifies the path to a CA certificate in PEM format. Optional; if not - // configured, the system's CA certificates will be used. - CAFile string - // Thumbprint of the VCenter's certificate thumbprint - Thumbprint string - // Name of the secret were vCenter credentials are present. - SecretName string - // Secret Namespace where secret will be present that has vCenter credentials. - SecretNamespace string - // Secret directory in the event that: - // 1) we don't want to use the k8s API to listen for changes to secrets - // 2) we are not in a k8s env, namely DC/OS, since CSI is CO agnostic - // Default: /etc/cloud/credentials - SecretsDirectory string -} - -// VirtualCenterConfig struct -type VirtualCenterConfig struct { - // vCenter username. - User string - // vCenter password in clear text. - Password string - // TenantRef (intentionally not exposed via the config) is a unique tenant ref to - // be used in place of the vcServer as the primary connection key. If one label is set, - // all virtual center configs must have a unique label. - TenantRef string - // vCenterIP - If this field in the config is set, it is assumed then that value in [VirtualCenter ""] - // is now the TenantRef above and this field is the actual VCenterIP. Otherwise for backward - // compatibility, the value by default is the IP or FQDN of the vCenter Server. - VCenterIP string - // vCenter port. - VCenterPort string - // True if vCenter uses self-signed cert. - InsecureFlag bool - // Datacenter in which VMs are located. - Datacenters string - // Soap round tripper count (retries = RoundTripper - 1) - RoundTripperCount uint - // Specifies the path to a CA certificate in PEM format. Optional; if not - // configured, the system's CA certificates will be used. - CAFile string - // Thumbprint of the VCenter's certificate thumbprint - Thumbprint string - // SecretRef (intentionally not exposed via the config) is a key to identify which - // InformerManager holds the secret - SecretRef string - // Name of the secret where vCenter credentials are present. - SecretName string - // Namespace where the secret will be present containing vCenter credentials. - SecretNamespace string - // IP Family enables the ability to support IPv4 or IPv6 - // Supported values are: - // ipv4 - IPv4 addresses only (Default) - // ipv6 - IPv6 addresses only - IPFamilyPriority []string -} - -// Labels struct -type Labels struct { - // Zone describes a zone - Zone string - // Region describes a region - Region string -} - -// Config is used to read and store information from the cloud configuration file -type Config struct { - // Global settings - Global Global - - // Virtual Center configurations - VirtualCenter map[string]*VirtualCenterConfig - - // Tag categories and tags which correspond to "built-in node labels: zones and region" - Labels Labels -} diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_ini_legacy.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_ini_legacy.go deleted file mode 100644 index d31eae21569..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_ini_legacy.go +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright 2018 The Kubernetes 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 config - -/* - TODO: - When the INI based cloud-config is deprecated. This file should be deleted. -*/ - -// GlobalINI are global values -type GlobalINI struct { - // vCenter username. - User string `gcfg:"user"` - // vCenter password in clear text. - Password string `gcfg:"password"` - // Deprecated. Use VirtualCenter to specify multiple vCenter Servers. - // vCenter IP. - VCenterIP string `gcfg:"server"` - // vCenter port. - VCenterPort string `gcfg:"port"` - // True if vCenter uses self-signed cert. - InsecureFlag bool `gcfg:"insecure-flag"` - // Datacenter in which VMs are located. - Datacenters string `gcfg:"datacenters"` - // Soap round tripper count (retries = RoundTripper - 1) - RoundTripperCount uint `gcfg:"soap-roundtrip-count"` - // Specifies the path to a CA certificate in PEM format. Optional; if not - // configured, the system's CA certificates will be used. - CAFile string `gcfg:"ca-file"` - // Thumbprint of the VCenter's certificate thumbprint - Thumbprint string `gcfg:"thumbprint"` - // Name of the secret were vCenter credentials are present. - SecretName string `gcfg:"secret-name"` - // Secret Namespace where secret will be present that has vCenter credentials. - SecretNamespace string `gcfg:"secret-namespace"` - // Secret directory in the event that: - // 1) we don't want to use the k8s API to listen for changes to secrets - // 2) we are not in a k8s env, namely DC/OS, since CSI is CO agnostic - // Default: /etc/cloud/credentials - SecretsDirectory string `gcfg:"secrets-directory"` - // Disable the vSphere CCM API - // Default: true - APIDisable bool `gcfg:"api-disable"` - // Configurable vSphere CCM API port - // Default: 43001 - APIBinding string `gcfg:"api-binding"` - // IP Family enables the ability to support IPv4 or IPv6 - // Supported values are: - // ipv4 - IPv4 addresses only (Default) - // ipv6 - IPv6 addresses only - IPFamily string `gcfg:"ip-family"` -} - -// VirtualCenterConfigINI contains information used to access a remote vCenter -// endpoint. -type VirtualCenterConfigINI struct { - // vCenter username. - User string `gcfg:"user"` - // vCenter password in clear text. - Password string `gcfg:"password"` - // TenantRef (intentionally not exposed via the config) is a unique tenant ref to - // be used in place of the vcServer as the primary connection key. If one label is set, - // all virtual center configs must have a unique label. - TenantRef string - // vCenterIP - If this field in the config is set, it is assumed then that value in [VirtualCenter ""] - // is now the TenantRef above and this field is the actual VCenterIP. Otherwise for backward - // compatibility, the value by default is the IP or FQDN of the vCenter Server. - VCenterIP string `gcfg:"server"` - // vCenter port. - VCenterPort string `gcfg:"port"` - // True if vCenter uses self-signed cert. - InsecureFlag bool `gcfg:"insecure-flag"` - // Datacenter in which VMs are located. - Datacenters string `gcfg:"datacenters"` - // Soap round tripper count (retries = RoundTripper - 1) - RoundTripperCount uint `gcfg:"soap-roundtrip-count"` - // Specifies the path to a CA certificate in PEM format. Optional; if not - // configured, the system's CA certificates will be used. - CAFile string `gcfg:"ca-file"` - // Thumbprint of the VCenter's certificate thumbprint - Thumbprint string `gcfg:"thumbprint"` - // SecretRef (intentionally not exposed via the config) is a key to identify which - // InformerManager holds the secret - SecretRef string - // Name of the secret where vCenter credentials are present. - SecretName string `gcfg:"secret-name"` - // Namespace where the secret will be present containing vCenter credentials. - SecretNamespace string `gcfg:"secret-namespace"` - // IP Family enables the ability to support IPv4 or IPv6 - // Supported values are: - // ipv4 - IPv4 addresses only (Default) - // ipv6 - IPv6 addresses only - IPFamily string `gcfg:"ip-family"` - // IPFamilyPriority (intentionally not exposed via the config) the list/priority of IP versions - IPFamilyPriority []string -} - -// LabelsINI tags categories and tags which correspond to "built-in node labels: zones and region" -type LabelsINI struct { - Zone string `gcfg:"zone"` - Region string `gcfg:"region"` -} - -// CommonConfigINI is used to read and store information from the cloud configuration file -type CommonConfigINI struct { - // Global values... - Global GlobalINI - - // Virtual Center configurations - VirtualCenter map[string]*VirtualCenterConfigINI - - // Tag categories and tags which correspond to "built-in node labels: zones and region" - Labels LabelsINI -} diff --git a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_yaml.go b/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_yaml.go deleted file mode 100644 index 472c279ec5a..00000000000 --- a/vendor/k8s.io/cloud-provider-vsphere/pkg/common/config/types_yaml.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2020 The Kubernetes 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 config - -/* - TODO: - When the INI based cloud-config is deprecated, this file should be renamed - from types_yaml.go to types.go and the structs within this file should be named: - - GlobalYAML -> Global - VirtualCenterConfigYAML -> VirtualCenterConfig - LabelsYAML -> Labels - ConfigYAML -> Config -*/ - -// GlobalYAML are global values -type GlobalYAML struct { - // vCenter username. - User string `yaml:"user"` - // vCenter password in clear text. - Password string `yaml:"password"` - // Deprecated. Use VirtualCenter to specify multiple vCenter Servers. - // vCenter IP. - VCenterIP string `yaml:"server"` - // vCenter port. - VCenterPort uint `yaml:"port"` - // True if vCenter uses self-signed cert. - InsecureFlag bool `yaml:"insecureFlag"` - // Datacenter in which VMs are located. - Datacenters []string `yaml:"datacenters"` - // Soap round tripper count (retries = RoundTripper - 1) - RoundTripperCount uint `yaml:"soapRoundtripCount"` - // Specifies the path to a CA certificate in PEM format. Optional; if not - // configured, the system's CA certificates will be used. - CAFile string `yaml:"caFile"` - // Thumbprint of the VCenter's certificate thumbprint - Thumbprint string `yaml:"thumbprint"` - // Name of the secret were vCenter credentials are present. - SecretName string `yaml:"secretName"` - // Secret Namespace where secret will be present that has vCenter credentials. - SecretNamespace string `yaml:"secretNamespace"` - // Secret directory in the event that: - // 1) we don't want to use the k8s API to listen for changes to secrets - // 2) we are not in a k8s env, namely DC/OS, since CSI is CO agnostic - // Default: /etc/cloud/credentials - SecretsDirectory string `yaml:"secretsDirectory"` - // Disable the vSphere CCM API - // Default: true - APIDisable bool `yaml:"apiDisable"` - // Configurable vSphere CCM API port - // Default: 43001 - APIBinding string `yaml:"apiBinding"` - // IP Family enables the ability to support IPv4 or IPv6 - // Supported values are: - // ipv4 - IPv4 addresses only (Default) - // ipv6 - IPv6 addresses only - IPFamilyPriority []string `yaml:"ipFamily"` -} - -// VirtualCenterConfigYAML contains information used to access a remote vCenter -// endpoint. -type VirtualCenterConfigYAML struct { - // vCenter username. - User string `yaml:"user"` - // vCenter password in clear text. - Password string `yaml:"password"` - // TenantRef (intentionally not exposed via the config) is a unique tenant ref to - // be used in place of the vcServer as the primary connection key. If one label is set, - // all virtual center configs must have a unique label. - TenantRef string - // vCenterIP - If this field in the config is set, it is assumed then that value in [VirtualCenter ""] - // is now the TenantRef above and this field is the actual VCenterIP. Otherwise for backward - // compatibility, the value by default is the IP or FQDN of the vCenter Server. - VCenterIP string `yaml:"server"` - // vCenter port. - VCenterPort uint `yaml:"port"` - // True if vCenter uses self-signed cert. - InsecureFlag bool `yaml:"insecureFlag"` - // Datacenter in which VMs are located. - Datacenters []string `yaml:"datacenters"` - // Soap round tripper count (retries = RoundTripper - 1) - RoundTripperCount uint `yaml:"soapRoundtripCount"` - // Specifies the path to a CA certificate in PEM format. Optional; if not - // configured, the system's CA certificates will be used. - CAFile string `yaml:"caFile"` - // Thumbprint of the VCenter's certificate thumbprint - Thumbprint string `yaml:"thumbprint"` - // SecretRef (intentionally not exposed via the config) is a key to identify which - // InformerManager holds the secret - SecretRef string - // Name of the secret where vCenter credentials are present. - SecretName string `yaml:"secretName"` - // Namespace where the secret will be present containing vCenter credentials. - SecretNamespace string `yaml:"secretNamespace"` - // IP Family enables the ability to support IPv4 or IPv6 - // Supported values are: - // ipv4 - IPv4 addresses only (Default) - // ipv6 - IPv6 addresses only - IPFamilyPriority []string `yaml:"ipFamily"` -} - -// LabelsYAML tags categories and tags which correspond to "built-in node labels: zones and region" -type LabelsYAML struct { - Zone string `yaml:"zone"` - Region string `yaml:"region"` -} - -// CommonConfigYAML is used to read and store information from the cloud configuration file -type CommonConfigYAML struct { - // Global values... - Global GlobalYAML - - // Virtual Center configurations - Vcenter map[string]*VirtualCenterConfigYAML - - // Tag categories and tags which correspond to "built-in node labels: zones and region" - Labels LabelsYAML -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7ddac52c7bd..2d0918fc3e9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2112,12 +2112,9 @@ github.com/openshift/library-go/pkg/verify/util # github.com/openshift/machine-api-operator v0.2.1-0.20251128002018-85c00c0d525f ## explicit; go 1.24.0 github.com/openshift/machine-api-operator/pkg/controller/machine -github.com/openshift/machine-api-operator/pkg/controller/vsphere -github.com/openshift/machine-api-operator/pkg/controller/vsphere/session github.com/openshift/machine-api-operator/pkg/metrics github.com/openshift/machine-api-operator/pkg/util github.com/openshift/machine-api-operator/pkg/util/conditions -github.com/openshift/machine-api-operator/pkg/util/ipam # github.com/openshift/machine-api-provider-gcp v0.0.1-0.20241021180644-0eca0846914a ## explicit; go 1.22.0 github.com/openshift/machine-api-provider-gcp/pkg/apis/gcpprovider/v1beta1 @@ -3100,12 +3097,6 @@ google.golang.org/protobuf/types/known/wrapperspb # gopkg.in/evanphx/json-patch.v4 v4.12.0 ## explicit gopkg.in/evanphx/json-patch.v4 -# gopkg.in/gcfg.v1 v1.2.3 -## explicit -gopkg.in/gcfg.v1 -gopkg.in/gcfg.v1/scanner -gopkg.in/gcfg.v1/token -gopkg.in/gcfg.v1/types # gopkg.in/inf.v0 v0.9.1 ## explicit gopkg.in/inf.v0 @@ -3118,9 +3109,6 @@ gopkg.in/natefinch/lumberjack.v2 # gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 ## explicit gopkg.in/tomb.v1 -# gopkg.in/warnings.v0 v0.1.2 -## explicit -gopkg.in/warnings.v0 # gopkg.in/yaml.v2 v2.4.0 ## explicit; go 1.15 gopkg.in/yaml.v2 @@ -3987,9 +3975,6 @@ k8s.io/client-go/util/jsonpath k8s.io/client-go/util/keyutil k8s.io/client-go/util/retry k8s.io/client-go/util/workqueue -# k8s.io/cloud-provider-vsphere v1.33.3 => github.com/openshift/cloud-provider-vsphere v1.19.1-0.20240626105621-6464d0bb4928 -## explicit; go 1.22.0 -k8s.io/cloud-provider-vsphere/pkg/common/config # k8s.io/cluster-registry v0.0.6 ## explicit k8s.io/cluster-registry/pkg/apis/clusterregistry/v1alpha1