Skip to content

Commit

Permalink
feat: configure Azure provider with task options
Browse files Browse the repository at this point in the history
Signed-off-by: András Jáky <ajaky@cisco.com>
  • Loading branch information
akijakya committed Mar 7, 2024
1 parent b37294a commit aee2c80
Show file tree
Hide file tree
Showing 4 changed files with 373 additions and 180 deletions.
50 changes: 50 additions & 0 deletions provider/v2/azure/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// 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 azure

type Option func(*Provider)

type ScannerTaskOption Option

func WithEnsureVMInfo(deps ...string) ScannerTaskOption {
return func(s *Provider) {
s.EnsureAssetVMInfo(deps)
}
}

func WithEnsureSnapshot(deps ...string) ScannerTaskOption {
return func(s *Provider) {
s.EnsureSnapshotWithCleanup(deps)
}
}

func WithEnsureDisk(deps ...string) ScannerTaskOption {
return func(s *Provider) {
s.EnsureDiskWithCleanup(deps)
}
}

func WithEnsureScannerVM(deps ...string) ScannerTaskOption {
return func(s *Provider) {
s.EnsureScannerVMWithCleanup(deps)
}
}

func WithEnsureAttachDiskToScannerVM(deps ...string) ScannerTaskOption {
return func(s *Provider) {
s.EnsureAttachDiskToScannerVM(deps)
}
}
21 changes: 18 additions & 3 deletions provider/v2/azure/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (p *Provider) Kind() apitypes.CloudProvider {
return apitypes.Azure
}

func New(_ context.Context) (*Provider, error) {
func New(_ context.Context, opts ...Option) (*Provider, error) {
config, err := NewConfig()
if err != nil {
return nil, fmt.Errorf("failed to load configuration: %w", err)
Expand All @@ -65,7 +65,7 @@ func New(_ context.Context) (*Provider, error) {
return nil, fmt.Errorf("failed to create compute client factory: %w", err)
}

return &Provider{
provider := &Provider{
Discoverer: &discoverer.Discoverer{
VMClient: computeClientFactory.NewVirtualMachinesClient(),
DisksClient: computeClientFactory.NewDisksClient(),
Expand All @@ -92,5 +92,20 @@ func New(_ context.Context) (*Provider, error) {
ScannerStorageContainerName: config.ScannerStorageContainerName,
},
Estimator: &estimator.Estimator{},
}, nil
}

for _, opt := range opts {
opt(provider)
}

// default to running all tasks if no options are provided
if len(opts) == 0 {
provider.EnsureAssetVMInfo(nil)
provider.EnsureScannerVMWithCleanup(nil)
provider.EnsureSnapshotWithCleanup([]string{scanner.EnsureAssetVMInfoTaskName})
provider.EnsureDiskWithCleanup([]string{scanner.EnsureAssetVMInfoTaskName, scanner.EnsureSnapshotTaskName})
provider.EnsureAttachDiskToScannerVM([]string{scanner.EnsureDiskTaskName, scanner.EnsureScannerVMTaskName})
}

return provider, nil
}
184 changes: 7 additions & 177 deletions provider/v2/azure/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ package scanner
import (
"context"
"fmt"
"strings"
"sync"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5"

"github.com/openclarity/vmclarity/provider"
"github.com/openclarity/vmclarity/provider/v2/azure/utils"
"github.com/openclarity/vmclarity/workflow"
workflowTypes "github.com/openclarity/vmclarity/workflow/types"
)
Expand Down Expand Up @@ -58,113 +57,19 @@ type Scanner struct {
ScannerSecurityGroup string
ScannerStorageAccountName string
ScannerStorageContainerName string
}

type AssetScanState struct {
assetVM armcompute.VirtualMachinesClientGetResponse
scannerVM armcompute.VirtualMachine
snapshot armcompute.Snapshot
disk armcompute.Disk
RunAssetScanTasks []*workflowTypes.Task[*AssetScanState]
RemoveAssetScanTasks []*workflowTypes.Task[*AssetScanState]
}

// nolint:cyclop
func (s *Scanner) RunAssetScan(ctx context.Context, config *provider.ScanJobConfig) error {
tasks := []*workflowTypes.Task[*AssetScanState]{
{
Name: "GetVMInfo",
Deps: nil,
Fn: func(ctx context.Context, state *AssetScanState) error {
vmInfo, err := config.AssetInfo.AsVMInfo()
if err != nil {
return provider.FatalErrorf("unable to get vminfo from asset: %w", err)
}

resourceGroup, vmName, err := resourceGroupAndNameFromInstanceID(vmInfo.InstanceID)
if err != nil {
return err
}

state.assetVM, err = s.VMClient.Get(ctx, resourceGroup, vmName, nil)
if err != nil {
_, err = utils.HandleAzureRequestError(err, "getting asset virtual machine %s", vmName)
return err
}

return nil
},
},
{
Name: "EnsureSnapshot",
Deps: []string{"GetVMInfo"},
Fn: func(ctx context.Context, state *AssetScanState) error {
var err error

state.snapshot, err = s.ensureSnapshotForVMRootVolume(ctx, config, state.assetVM.VirtualMachine)
if err != nil {
return fmt.Errorf("failed to ensure snapshot for vm root volume: %w", err)
}

return nil
},
},
{
Name: "EnsureDisk",
Deps: []string{"GetVMInfo", "EnsureSnapshot"},
Fn: func(ctx context.Context, state *AssetScanState) error {
var err error

if *state.assetVM.Location == s.ScannerLocation {
state.disk, err = s.ensureManagedDiskFromSnapshot(ctx, config, state.snapshot)
if err != nil {
return fmt.Errorf("failed to ensure managed disk created from snapshot: %w", err)
}
} else {
state.disk, err = s.ensureManagedDiskFromSnapshotInDifferentRegion(ctx, config, state.snapshot)
if err != nil {
return fmt.Errorf("failed to ensure managed disk from snapshot in different region: %w", err)
}
}

return nil
},
},
{
Name: "EnsureScannerVM",
Deps: []string{"EnsureDisk"},
Fn: func(ctx context.Context, state *AssetScanState) error {
networkInterface, err := s.ensureNetworkInterface(ctx, config)
if err != nil {
return fmt.Errorf("failed to ensure scanner network interface: %w", err)
}

state.scannerVM, err = s.ensureScannerVirtualMachine(ctx, config, networkInterface)
if err != nil {
return fmt.Errorf("failed to ensure scanner virtual machine: %w", err)
}

return nil
},
},
{
Name: "AttachDiskToScannerVM",
Deps: []string{"EnsureScannerVM", "EnsureDisk"},
Fn: func(ctx context.Context, state *AssetScanState) error {
err := s.ensureDiskAttachedToScannerVM(ctx, state.scannerVM, state.disk)
if err != nil {
return fmt.Errorf("failed to ensure asset disk is attached to virtual machine: %w", err)
}

return nil
},
},
}

workflow, err := workflow.New[*AssetScanState, *workflowTypes.Task[*AssetScanState]](tasks)
workflow, err := workflow.New[*AssetScanState, *workflowTypes.Task[*AssetScanState]](s.RunAssetScanTasks)
if err != nil {
return fmt.Errorf("failed to create RunAssetScan workflow: %w", err)
}

err = workflow.Run(ctx, &AssetScanState{})
err = workflow.Run(ctx, &AssetScanState{config: config, mu: &sync.RWMutex{}})
if err != nil {
return fmt.Errorf("failed to run RunAssetScan workflow: %w", err)
}
Expand All @@ -173,90 +78,15 @@ func (s *Scanner) RunAssetScan(ctx context.Context, config *provider.ScanJobConf
}

func (s *Scanner) RemoveAssetScan(ctx context.Context, config *provider.ScanJobConfig) error {
tasks := []*workflowTypes.Task[*AssetScanState]{
{
Name: "EnsureScannerVMDeleted",
Deps: nil,
Fn: func(ctx context.Context, state *AssetScanState) error {
err := s.ensureScannerVirtualMachineDeleted(ctx, config)
if err != nil {
return fmt.Errorf("failed to ensure scanner virtual machine deleted: %w", err)
}
return nil
},
},
{
Name: "EnsureNetworkInterfaceDeleted",
Deps: nil, // []string{"EnsureScannerVMDeleted"},
Fn: func(ctx context.Context, state *AssetScanState) error {
err := s.ensureNetworkInterfaceDeleted(ctx, config)
if err != nil {
return fmt.Errorf("failed to ensure network interface deleted: %w", err)
}

return nil
},
},
{
Name: "EnsureTargetDiskDeleted",
Deps: nil, // []string{"EnsureNetworkInterfaceDeleted"},
Fn: func(ctx context.Context, state *AssetScanState) error {
err := s.ensureTargetDiskDeleted(ctx, config)
if err != nil {
return fmt.Errorf("failed to ensure asset disk deleted: %w", err)
}

return nil
},
},
{
Name: "EnsureBlobDeleted",
Deps: nil, // []string{"EnsureTargetDiskDeleted"},
Fn: func(ctx context.Context, state *AssetScanState) error {
err := s.ensureBlobDeleted(ctx, config)
if err != nil {
return fmt.Errorf("failed to ensure snapshot copy blob deleted: %w", err)
}

return nil
},
},
{
Name: "EnsureSnapshotDeleted",
Deps: nil, // []string{"EnsureBlobDeleted"},
Fn: func(ctx context.Context, state *AssetScanState) error {
err := s.ensureSnapshotDeleted(ctx, config)
if err != nil {
return fmt.Errorf("failed to ensure snapshot deleted: %w", err)
}

return nil
},
},
}

workflow, err := workflow.New[*AssetScanState, *workflowTypes.Task[*AssetScanState]](tasks)
workflow, err := workflow.New[*AssetScanState, *workflowTypes.Task[*AssetScanState]](s.RemoveAssetScanTasks)
if err != nil {
return fmt.Errorf("failed to create RemoveAssetScan workflow: %w", err)
}

err = workflow.Run(ctx, &AssetScanState{})
err = workflow.Run(ctx, &AssetScanState{config: config, mu: &sync.RWMutex{}})
if err != nil {
return fmt.Errorf("failed to run RemoveAssetScan workflow: %w", err)
}

return nil
}

// Example Instance ID:
//
// /subscriptions/ecad88af-09d5-4725-8d80-906e51fddf02/resourceGroups/vmclarity-sambetts-dev/providers/Microsoft.Compute/virtualMachines/vmclarity-server
//
// Will return "vmclarity-sambetts-dev" and "vmclarity-server".
func resourceGroupAndNameFromInstanceID(instanceID string) (string, string, error) {
idParts := strings.Split(instanceID, "/")
if len(idParts) != instanceIDPartsLength {
return "", "", provider.FatalErrorf("asset instance id in unexpected format got: %s", idParts)
}
return idParts[resourceGroupPartIdx], idParts[vmNamePartIdx], nil
}
Loading

0 comments on commit aee2c80

Please sign in to comment.