Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hostType parameter for the AzureStackHCIMachine #260

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/v1alpha3/azurestackhciloadbalancer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ type AzureStackHCILoadBalancerSpec struct {
SSHPublicKey string `json:"sshPublicKey"`
Image Image `json:"image"`
VMSize string `json:"vmSize"`

// Number of desired loadbalancer machines. Defaults to 1.
// This is a pointer to distinguish between explicit zero and not specified.
// +optional
Expand Down
1 change: 0 additions & 1 deletion api/v1alpha4/azurestackhciloadbalancer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ type AzureStackHCILoadBalancerSpec struct {
SSHPublicKey string `json:"sshPublicKey"`
Image Image `json:"image"`
VMSize string `json:"vmSize"`

// Number of desired loadbalancer machines. Defaults to 1.
// This is a pointer to distinguish between explicit zero and not specified.
// +optional
Expand Down
3 changes: 2 additions & 1 deletion api/v1beta1/azurestackhciloadbalancer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ type AzureStackHCILoadBalancerSpec struct {
SSHPublicKey string `json:"sshPublicKey"`
Image Image `json:"image"`
VMSize string `json:"vmSize"`

// +optional
HostType HostType `json:"hostType,omitempty"`
// +optional
StorageContainer string `json:"storageContainer"`

Expand Down
2 changes: 2 additions & 0 deletions api/v1beta1/azurestackhcimachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ type AzureStackHCIMachineSpec struct {

// +optional
NetworkInterfaces NetworkInterfaces `json:"networkInterfaces,omitempty"`
// +optional
HostType HostType `json:"hostType,omitempty"`
}

// AzureStackHCIMachineStatus defines the observed state of AzureStackHCIMachine
Expand Down
2 changes: 2 additions & 0 deletions api/v1beta1/azurestackhcivirtualmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ type AzureStackHCIVirtualMachineSpec struct {

// +optional
NetworkInterfaces NetworkInterfaces `json:"networkInterfaces,omitempty"`
// +optional
HostType HostType `json:"hostType,omitempty"`
}

// AzureStackHCIVirtualMachineStatus defines the observed state of AzureStackHCIVirtualMachine
Expand Down
12 changes: 12 additions & 0 deletions api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,15 @@ const (
AzureOperationIDAnnotationKey = "management.azure.com/operationId"
AzureCorrelationIDAnnotationKey = "management.azure.com/correlationId"
)

// HostType specifies what type of machine a node should be deployed on.
type HostType string

const (
// HostTypeVM specifies that the node should be deployed on a virtual machine.
// Default value.
HostTypeVM = HostType("vm")

// HostTypeBareMetal specifies that the node should be deployed on a bare metal machine.
HostTypeBareMetal = HostType("baremetal")
)
10 changes: 10 additions & 0 deletions cloud/converters/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,13 @@ func SDKToVM(v compute.VirtualMachine) (*infrav1.VM, error) {
}
return vm, nil
}

// BareMetalMachineConvertToCAPH converts an SDK BareMetalMachine to the provider VM type.
func BareMetalMachineConvertToCAPH(v compute.BareMetalMachine) (*infrav1.VM, error) {
vm := &infrav1.VM{
ID: to.String(v.ID),
Name: to.String(v.Name),
State: infrav1.VMStateSucceeded, // Hard-coded for now until we expose provisioning state
}
return vm, nil
}
16 changes: 12 additions & 4 deletions cloud/services/virtualmachines/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package virtualmachines
import (
azurestackhci "github.com/microsoft/cluster-api-provider-azurestackhci/cloud"
"github.com/microsoft/cluster-api-provider-azurestackhci/cloud/scope"
"github.com/microsoft/moc-sdk-for-go/services/compute/baremetalmachine"
"github.com/microsoft/moc-sdk-for-go/services/compute/virtualmachine"
"github.com/microsoft/moc/pkg/auth"
)
Expand All @@ -28,8 +29,9 @@ var _ azurestackhci.Service = (*Service)(nil)

// Service provides operations on virtual machines.
type Service struct {
Client virtualmachine.VirtualMachineClient
Scope scope.ScopeInterface
Client virtualmachine.VirtualMachineClient
BareMetalClient baremetalmachine.BareMetalMachineClient
Scope scope.ScopeInterface
}

// getVirtualMachinesClient creates a new virtual machines client.
Expand All @@ -38,10 +40,16 @@ func getVirtualMachinesClient(cloudAgentFqdn string, authorizer auth.Authorizer)
return *vmClient
}

func getBareMetalMachinesClient(cloudAgentFqdn string, authorizer auth.Authorizer) baremetalmachine.BareMetalMachineClient {
bareMetalClient, _ := baremetalmachine.NewBareMetalMachineClient(cloudAgentFqdn, authorizer)
return *bareMetalClient
}

// NewService creates a new virtual machines service.
func NewService(scope scope.ScopeInterface) *Service {
return &Service{
Client: getVirtualMachinesClient(scope.GetCloudAgentFqdn(), scope.GetAuthorizer()),
Scope: scope,
Client: getVirtualMachinesClient(scope.GetCloudAgentFqdn(), scope.GetAuthorizer()),
BareMetalClient: getBareMetalMachinesClient(scope.GetCloudAgentFqdn(), scope.GetAuthorizer()),
Scope: scope,
}
}
149 changes: 115 additions & 34 deletions cloud/services/virtualmachines/virtualmachines.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/microsoft/moc-sdk-for-go/services/network"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"k8s.io/klog"
)

const (
Expand All @@ -54,24 +55,43 @@ type Spec struct {
CustomData string
VMType compute.VMType
StorageContainer string
HostType infrav1.HostType
}

// Get provides information about a virtual machine.
func (s *Service) Get(ctx context.Context, spec interface{}) (interface{}, error) {
var err error
vmSpec, ok := spec.(*Spec)
if !ok {
return compute.VirtualMachine{}, errors.New("invalid vm specification")
return nil, errors.New("invalid vm specification")
}

vm, err := s.Client.Get(ctx, s.Scope.GetResourceGroup(), vmSpec.Name)
if err != nil {
return nil, err
}
if vm == nil || len(*vm) == 0 {
return nil, errors.Wrapf(err, "vm %s not found", vmSpec.Name)
}
switch vmSpec.HostType {
case infrav1.HostTypeBareMetal:
var baremetalmachine *[]compute.BareMetalMachine

baremetalmachine, err = s.BareMetalClient.Get(ctx, s.Scope.GetResourceGroup(), vmSpec.Name)
if err != nil {
return nil, err
}

if baremetalmachine == nil || len(*baremetalmachine) == 0 {
return nil, errors.Errorf("bare-metal machine %s not found", vmSpec.Name)
}

return converters.SDKToVM((*vm)[0])
return converters.BareMetalMachineConvertToCAPH((*baremetalmachine)[0])

default:
vm, err := s.Client.Get(ctx, s.Scope.GetResourceGroup(), vmSpec.Name)
if err != nil {
return nil, err
}
if vm == nil || len(*vm) == 0 {
return nil, errors.Errorf("vm %s not found", vmSpec.Name)
}

return converters.SDKToVM((*vm)[0])
}
}

// Reconcile gets/creates/updates a virtual machine.
Expand All @@ -88,16 +108,22 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error {
}

logger := s.Scope.GetLogger()
logger.Info("getting nic", "nic", vmSpec.NICName)
nicInterface, err := networkinterfaces.NewService(s.Scope).Get(ctx, &networkinterfaces.Spec{Name: vmSpec.NICName})
if err != nil {
return err
}
nic, ok := nicInterface.(network.Interface)
if !ok {
return errors.New("error getting network interface")
nicStr := ""

// ignore for baremetal
if vmSpec.HostType != infrav1.HostTypeBareMetal {
logger.Info("getting nic", "nic", vmSpec.NICName)
nicInterface, err := networkinterfaces.NewService(s.Scope).Get(ctx, &networkinterfaces.Spec{Name: vmSpec.NICName})
if err != nil {
return err
}
nic, ok := nicInterface.(network.Interface)
if !ok {
return errors.New("error getting network interface")
}
logger.Info("got nic", "nic", vmSpec.NICName)
nicStr = *nic.Name
}
logger.Info("got nic", "nic", vmSpec.NICName)

logger.Info("creating vm",
"Name", vmSpec.Name,
Expand Down Expand Up @@ -156,7 +182,7 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error {
NetworkProfile: &compute.NetworkProfile{
NetworkInterfaces: &[]compute.NetworkInterfaceReference{
{
ID: nic.Name,
ID: &nicStr,
},
},
},
Expand All @@ -181,21 +207,68 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error {
}
}

_, err = s.Client.CreateOrUpdate(
ctx,
s.Scope.GetResourceGroup(),
vmSpec.Name,
&virtualMachine)
telemetry.WriteMocOperationLog(logger, telemetry.CreateOrUpdate, s.Scope.GetCustomResourceTypeWithName(), telemetry.VirtualMachine,
telemetry.GenerateMocResourceName(s.Scope.GetResourceGroup(), vmSpec.Name), nil, err)
if err != nil {
return errors.Wrapf(err, "cannot create vm")
switch vmSpec.HostType {
case infrav1.HostTypeBareMetal:
_, err := s.createOrUpdateBareMetal(
ctx,
&virtualMachine)
if err != nil {
return errors.Wrapf(err, "cannot create bare-metal machine")
}

default:
_, err = s.Client.CreateOrUpdate(
ctx,
s.Scope.GetResourceGroup(),
vmSpec.Name,
&virtualMachine)
telemetry.WriteMocOperationLog(logger, telemetry.CreateOrUpdate, s.Scope.GetCustomResourceTypeWithName(), telemetry.VirtualMachine,
telemetry.GenerateMocResourceName(s.Scope.GetResourceGroup(), vmSpec.Name), nil, err)
if err != nil {
return errors.Wrapf(err, "cannot create vm")
}
}

logger.Info("successfully created vm", "name", vmSpec.Name)
return err
}

func (s *Service) createOrUpdateBareMetal(ctx context.Context, virtualMachine *compute.VirtualMachine) (*compute.BareMetalMachine, error) {
// Create a new baremetal machine
bareMetalMachine := &compute.BareMetalMachine{
Name: virtualMachine.Name,
}

bareMetalMachine.BareMetalMachineProperties = &compute.BareMetalMachineProperties{
StorageProfile: &compute.BareMetalMachineStorageProfile{
ImageReference: &compute.BareMetalMachineImageReference{
ID: virtualMachine.VirtualMachineProperties.StorageProfile.ImageReference.ID,
Name: virtualMachine.VirtualMachineProperties.StorageProfile.ImageReference.Name,
},
},
OsProfile: &compute.BareMetalMachineOSProfile{
ComputerName: virtualMachine.VirtualMachineProperties.OsProfile.ComputerName,
AdminUsername: virtualMachine.VirtualMachineProperties.OsProfile.AdminUsername,
AdminPassword: virtualMachine.VirtualMachineProperties.OsProfile.AdminPassword,
CustomData: virtualMachine.VirtualMachineProperties.OsProfile.CustomData,
LinuxConfiguration: virtualMachine.VirtualMachineProperties.OsProfile.LinuxConfiguration,
},
SecurityProfile: virtualMachine.VirtualMachineProperties.SecurityProfile,
ProvisioningState: virtualMachine.VirtualMachineProperties.ProvisioningState,
Statuses: virtualMachine.VirtualMachineProperties.Statuses,
}

// Try to apply the update.
_, err := s.BareMetalClient.CreateOrUpdate(ctx, s.Scope.GetResourceGroup(), *bareMetalMachine.Name, bareMetalMachine)

if err != nil {
return nil, errors.Wrap(err, "Failed to create baremetal machine.")
}

// klog.V(2).Infof("Successfully created baremetal machine %s ", bareMetalMachine.Name)
return bareMetalMachine, nil
}

// Delete deletes the virtual machine with the provided name.
func (s *Service) Delete(ctx context.Context, spec interface{}) error {
telemetry.WriteMocInfoLog(ctx, s.Scope)
Expand All @@ -204,19 +277,27 @@ func (s *Service) Delete(ctx context.Context, spec interface{}) error {
return errors.New("invalid vm Specification")
}
logger := s.Scope.GetLogger()
logger.Info("deleting vm", "vm", vmSpec.Name)
err := s.Client.Delete(ctx, s.Scope.GetResourceGroup(), vmSpec.Name)
telemetry.WriteMocOperationLog(s.Scope.GetLogger(), telemetry.Delete, s.Scope.GetCustomResourceTypeWithName(), telemetry.VirtualMachine,
telemetry.GenerateMocResourceName(s.Scope.GetResourceGroup(), vmSpec.Name), nil, err)

var err error
switch vmSpec.HostType {
case infrav1.HostTypeBareMetal:
klog.V(2).Infof("deleting bare-metal machine %s ", vmSpec.Name)
err = s.BareMetalClient.Delete(ctx, s.Scope.GetResourceGroup(), vmSpec.Name)
default:
logger.Info("deleting vm", "vm", vmSpec.Name)
err = s.Client.Delete(ctx, s.Scope.GetResourceGroup(), vmSpec.Name)
telemetry.WriteMocOperationLog(s.Scope.GetLogger(), telemetry.Delete, s.Scope.GetCustomResourceTypeWithName(), telemetry.VirtualMachine,
telemetry.GenerateMocResourceName(s.Scope.GetResourceGroup(), vmSpec.Name), nil, err)
}
if err != nil && azurestackhci.ResourceNotFound(err) {
// already deleted
return nil
}
if err != nil {
return errors.Wrapf(err, "failed to delete vm %s in resource group %s", vmSpec.Name, s.Scope.GetResourceGroup())
return errors.Wrapf(err, "failed to delete %s %s in resource group %s", vmSpec.HostType, vmSpec.Name, s.Scope.GetResourceGroup())
}

logger.Info("successfully deleted vm", "vm", vmSpec.Name)
klog.V(2).Infof("successfully deleted %s %s ", vmSpec.HostType, vmSpec.Name)
return err
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ spec:
description: AzureStackHCILoadBalancer is used to declare the AzureStackHCILoadBalancerSpec
if a LoadBalancer is desired for the AzureStackHCICluster.
properties:
hostType:
description: HostType specifies what type of machine a node should
be deployed on.
type: string
image:
description: 'Image defines information about the image to use
for VM creation. There are three ways to specify an image: by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ spec:
type: object
spec:
properties:
hostType:
description: HostType specifies what type of machine a node should
be deployed on.
type: string
image:
description: 'Image defines information about the image to use for
VM creation. There are three ways to specify an image: by ID, by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ spec:
id:
type: string
type: object
hostType:
description: HostType specifies what type of machine a node should
be deployed on.
type: string
image:
description: 'Image defines information about the image to use for
VM creation. There are three ways to specify an image: by ID, by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ spec:
id:
type: string
type: object
hostType:
description: HostType specifies what type of machine a node
should be deployed on.
type: string
image:
description: 'Image defines information about the image to
use for VM creation. There are three ways to specify an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ spec:
type: string
clusterName:
type: string
hostType:
description: HostType specifies what type of machine a node should
be deployed on.
type: string
identity:
description: VMIdentity defines the identity of the virtual machine,
if configured.
Expand Down
Loading