Skip to content

Commit

Permalink
vsphere: set providerID
Browse files Browse the repository at this point in the history
  • Loading branch information
enxebre committed Jan 9, 2020
1 parent 463c63d commit ca9022d
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 12 deletions.
18 changes: 14 additions & 4 deletions pkg/controller/vsphere/machine_scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ func newMachineScope(params machineScopeParams) (*machineScope, error) {
if err != nil {
return nil, fmt.Errorf("%v: error getting credentials: %v", params.machine.GetName(), err)
}
if providerSpec.Workspace == nil {
return nil, fmt.Errorf("%v: no workspace provided", params.machine.GetName())
}
authSession, err := session.GetOrCreate(context.TODO(),
providerSpec.Workspace.Server, providerSpec.Workspace.Datacenter,
user, password)
Expand All @@ -78,19 +81,26 @@ func newMachineScope(params machineScopeParams) (*machineScope, error) {

// Patch patches the machine spec and machine status after reconciling.
func (s *machineScope) PatchMachine() error {
klog.V(3).Infof("%v: patching", s.machine.GetName())
// TODO: patch machine
klog.V(3).Infof("%v: patching machine", s.machine.GetName())

providerStatus, err := apivshpere.RawExtensionFromProviderStatus(s.providerStatus)
if err != nil {
return machineapierros.InvalidMachineConfiguration("failed to get machine provider status: %v", err.Error())
}

s.machine.Status.ProviderStatus = providerStatus

// 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
}

// patch status
if err := s.client.Status().Patch(context.Background(), s.machine, s.machineToBePatched); err != nil {
klog.Errorf("Failed to update machine %q: %v", s.machine.GetName(), err)
klog.Errorf("Failed to patch machine status %q: %v", s.machine.GetName(), err)
return err
}

return nil
}

Expand Down
116 changes: 116 additions & 0 deletions pkg/controller/vsphere/machine_scope_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package vsphere

import (
"context"
"testing"

machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1"
apivsphere "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

Expand Down Expand Up @@ -134,3 +138,115 @@ func TestGetCredentialsSecret(t *testing.T) {
})
}
}

func TestPatchMachine(t *testing.T) {
model, _, server := initSimulator(t)
defer model.Remove()
defer server.Close()

// fake objects for newMachineScope()
password, _ := server.URL.User.Password()
namespace := "test"
credentialsSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: namespace,
},
Data: map[string][]byte{
credentialsSecretUser: []byte(server.URL.User.Username()),
credentialsSecretPassword: []byte(password),
},
}

// original objects
originalProviderSpec := apivsphere.VSphereMachineProviderSpec{
CredentialsSecret: &corev1.LocalObjectReference{
Name: "test",
},

Workspace: &apivsphere.Workspace{
Server: server.URL.Host,
Folder: "test",
},
}
rawProviderSpec, err := apivsphere.RawExtensionFromProviderSpec(&originalProviderSpec)
if err != nil {
t.Fatal(err)
}

originalProviderStatus := &apivsphere.VSphereMachineProviderStatus{
TaskRef: "test",
}
rawProviderStatus, err := apivsphere.RawExtensionFromProviderStatus(originalProviderStatus)
if err != nil {
t.Fatal(err)
}

originalMachine := &machinev1.Machine{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: namespace,
},
TypeMeta: metav1.TypeMeta{
Kind: "Machine",
},
Spec: machinev1.MachineSpec{
ProviderSpec: machinev1.ProviderSpec{
Value: rawProviderSpec,
},
},
Status: machinev1.MachineStatus{
ProviderStatus: rawProviderStatus,
},
}

// expected objects
expectedMachine := originalMachine.DeepCopy()
providerID := "mutated"
expectedMachine.Spec.ProviderID = &providerID
expectedMachine.Status.Addresses = []corev1.NodeAddress{
{
Type: corev1.NodeInternalDNS,
Address: "127.0.0.1",
},
}
expectedProviderStatus := &apivsphere.VSphereMachineProviderStatus{
TaskRef: "mutated",
}
rawProviderStatus, err = apivsphere.RawExtensionFromProviderStatus(expectedProviderStatus)
if err != nil {
t.Fatal(err)
}
expectedMachine.Status.ProviderStatus = rawProviderStatus

// machineScope
if err := machinev1.AddToScheme(scheme.Scheme); err != nil {
t.Fatal(err)
}
fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, credentialsSecret, originalMachine)
machineScope, err := newMachineScope(machineScopeParams{
client: fakeClient,
Context: context.TODO(),
machine: originalMachine,
})
if err != nil {
t.Fatal(err)
}

// mutations
machineScope.machine.Spec.ProviderID = expectedMachine.Spec.ProviderID
machineScope.machine.Status.Addresses = expectedMachine.Status.Addresses
machineScope.providerStatus = expectedProviderStatus

if err := machineScope.PatchMachine(); err != nil {
t.Errorf("unexpected error")
}
gotMachine := &machinev1.Machine{}
if err := machineScope.client.Get(context.TODO(), runtimeclient.ObjectKey{Name: "test", Namespace: namespace}, gotMachine); err != nil {
t.Fatal(err)
}

if !equality.Semantic.DeepEqual(gotMachine, expectedMachine) {
t.Errorf("expected: %+v, got: %+v", expectedMachine, gotMachine)
}
}
40 changes: 32 additions & 8 deletions pkg/controller/vsphere/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strings"

"github.com/google/uuid"
machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1"
vsphereapi "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1"
machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine"
Expand All @@ -19,10 +20,11 @@ import (
)

const (
minMemMB = 2048
minCPU = 2
diskMoveType = string(types.VirtualMachineRelocateDiskMoveOptionsMoveAllDiskBackingsAndConsolidate)
ethCardType = "vmxnet3"
minMemMB = 2048
minCPU = 2
diskMoveType = string(types.VirtualMachineRelocateDiskMoveOptionsMoveAllDiskBackingsAndConsolidate)
ethCardType = "vmxnet3"
providerIDPrefix = "vsphere://"
)

// Reconciler runs the logic to reconciles a machine resource towards its desired state
Expand Down Expand Up @@ -75,15 +77,15 @@ func (r *Reconciler) update() error {
return fmt.Errorf("%v: failed validating machine provider spec: %v", r.machine.GetName(), err)
}

taskRef, err := r.session.GetTask(r.Context, r.providerStatus.TaskRef)
motask, err := r.session.GetTask(r.Context, r.providerStatus.TaskRef)
if err != nil {
if !isRetrieveMONotFound(r.providerStatus.TaskRef, err) {
return err
}
}
if taskIsFinished, err := taskIsFinished(taskRef); err != nil || !taskIsFinished {
if taskIsFinished, err := taskIsFinished(motask); err != nil || !taskIsFinished {
if !taskIsFinished {
return fmt.Errorf("task %v has not finished", taskRef.Value)
return fmt.Errorf("task %v has not finished", motask.Reference().Value)
}
return err
}
Expand Down Expand Up @@ -135,12 +137,34 @@ func (r *Reconciler) delete() error {
// reconcileMachineWithCloudState reconcile machineSpec and status with the latest cloud state
func (r *Reconciler) reconcileMachineWithCloudState(vm *virtualMachine) error {
klog.V(3).Infof("%v: reconciling machine with cloud state", r.machine.GetName())
// TODO: reconcile providerID
// TODO: reconcile task

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())
return r.reconcileNetwork(vm)
}

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 {
Expand Down
66 changes: 66 additions & 0 deletions pkg/controller/vsphere/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,72 @@ func TestReconcileNetwork(t *testing.T) {
// TODO: add more cases by adding network devices to the NewVirtualMachine() object
}

func TestReconcileProviderID(t *testing.T) {
model, session, server := initSimulator(t)
defer model.Remove()
defer server.Close()

managedObj := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
objectVM := object.NewVirtualMachine(session.Client.Client, managedObj.Reference())
managedObjRef := objectVM.Reference()

vm := &virtualMachine{
Context: context.TODO(),
Obj: objectVM,
Ref: managedObjRef,
}

r := &Reconciler{
machineScope: &machineScope{
Context: context.TODO(),
session: session,
machine: &machinev1.Machine{
Status: machinev1.MachineStatus{},
},
},
}

if err := r.reconcileProviderID(vm); err != nil {
t.Errorf("unexpected error")
}

if *r.machine.Spec.ProviderID != providerIDPrefix+vm.Obj.UUID(context.TODO()) {
t.Errorf("failed to match expected providerID pattern, expected: %v, got: %v", providerIDPrefix+vm.Obj.UUID(context.TODO()), *r.machine.Spec.ProviderID)
}
}

func TestConvertUUIDToProviderID(t *testing.T) {
validUUID := "f7c371d6-2003-5a48-9859-3bc9a8b08908"
testCases := []struct {
testCase string
UUID string
expected string
}{
{
testCase: "valid",
UUID: validUUID,
expected: providerIDPrefix + validUUID,
},
{
testCase: "invalid",
UUID: "f7c371d6",
expected: "",
},
}

for _, tc := range testCases {
t.Run(tc.testCase, func(t *testing.T) {
got, err := convertUUIDToProviderID(tc.UUID)
if got != tc.expected {
t.Errorf("expected: %v, got: %v", tc.expected, got)
}
if tc.expected == "" && err == nil {
t.Errorf("expected error, got %v", err)
}
})
}
}

// TODO TestCreate()
// TODO TestUpdate()
// TODO TestExist()
Expand Down

0 comments on commit ca9022d

Please sign in to comment.