From b6db39c574edc4826855d1075d11ee70d66f62c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Thu, 22 Feb 2024 10:32:14 +0100 Subject: [PATCH 1/9] refactor: implement Estimator in Azure providerv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/estimator/estimator.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/provider/v2/azure/estimator/estimator.go b/provider/v2/azure/estimator/estimator.go index 5b79b9844..1d7bf689e 100644 --- a/provider/v2/azure/estimator/estimator.go +++ b/provider/v2/azure/estimator/estimator.go @@ -22,11 +22,8 @@ import ( "github.com/openclarity/vmclarity/provider" ) -var _ provider.Estimator = &Estimator{} - type Estimator struct{} func (e *Estimator) Estimate(ctx context.Context, stats apitypes.AssetScanStats, asset *apitypes.Asset, template *apitypes.AssetScanTemplate) (*apitypes.Estimation, error) { - // TODO implement me - panic("implement me") + return &apitypes.Estimation{}, provider.FatalErrorf("Not Implemented") } From 6f5785a60d0bb43acd23c7a17bf432d98e3980e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Thu, 22 Feb 2024 10:42:57 +0100 Subject: [PATCH 2/9] refactor: implement Kind method in Azure providerv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/provider.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/provider/v2/azure/provider.go b/provider/v2/azure/provider.go index f09cc0b3d..455d8a2ae 100644 --- a/provider/v2/azure/provider.go +++ b/provider/v2/azure/provider.go @@ -19,14 +19,11 @@ import ( "context" apitypes "github.com/openclarity/vmclarity/api/types" - "github.com/openclarity/vmclarity/provider" - "github.com/openclarity/vmclarity/provider/v2/aws/discoverer" - "github.com/openclarity/vmclarity/provider/v2/aws/estimator" - "github.com/openclarity/vmclarity/provider/v2/aws/scanner" + "github.com/openclarity/vmclarity/provider/v2/azure/discoverer" + "github.com/openclarity/vmclarity/provider/v2/azure/estimator" + "github.com/openclarity/vmclarity/provider/v2/azure/scanner" ) -var _ provider.Provider = &Provider{} - type Provider struct { *discoverer.Discoverer *scanner.Scanner @@ -34,8 +31,7 @@ type Provider struct { } func (p *Provider) Kind() apitypes.CloudProvider { - // TODO implement me - panic("implement me") + return apitypes.Azure } func New(_ context.Context) (*Provider, error) { From 598fc27a1b97792ee7b4fa096b162c85cad3af9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Thu, 22 Feb 2024 10:23:48 +0100 Subject: [PATCH 3/9] refactor: implement Discoverer in Azure providerv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/common/config.go | 140 +++++++++++++++++++++ provider/v2/azure/discoverer/discoverer.go | 137 +++++++++++++++++++- provider/v2/azure/provider.go | 34 ++++- 3 files changed, 303 insertions(+), 8 deletions(-) create mode 100644 provider/v2/azure/common/config.go diff --git a/provider/v2/azure/common/config.go b/provider/v2/azure/common/config.go new file mode 100644 index 000000000..939be22e5 --- /dev/null +++ b/provider/v2/azure/common/config.go @@ -0,0 +1,140 @@ +// 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 common + +import ( + "encoding/base64" + "errors" + "fmt" + + "github.com/mitchellh/mapstructure" + "github.com/spf13/viper" +) + +const ( + DefaultEnvPrefix = "VMCLARITY_AZURE" +) + +type AzurePublicKey string + +func (a *AzurePublicKey) UnmarshalText(text []byte) error { + if len(text) != 0 { + publicKey, err := base64.StdEncoding.DecodeString(string(text)) + if err != nil { + return fmt.Errorf("failed to decode azure scanner public key from base64: %w", err) + } + *a = AzurePublicKey(publicKey) + } + return nil +} + +type Config struct { + SubscriptionID string `mapstructure:"subscription_id"` + ScannerLocation string `mapstructure:"scanner_location"` + ScannerResourceGroup string `mapstructure:"scanner_resource_group"` + ScannerSubnet string `mapstructure:"scanner_subnet_id"` + ScannerPublicKey AzurePublicKey `mapstructure:"scanner_public_key"` + ScannerVMSize string `mapstructure:"scanner_vm_size"` + ScannerImagePublisher string `mapstructure:"scanner_image_publisher"` + ScannerImageOffer string `mapstructure:"scanner_image_offer"` + ScannerImageSKU string `mapstructure:"scanner_image_sku"` + ScannerImageVersion string `mapstructure:"scanner_image_version"` + ScannerSecurityGroup string `mapstructure:"scanner_security_group"` + ScannerStorageAccountName string `mapstructure:"scanner_storage_account_name"` + ScannerStorageContainerName string `mapstructure:"scanner_storage_container_name"` +} + +func NewConfig() (*Config, error) { + // Avoid modifying the global instance + v := viper.New() + + v.SetEnvPrefix(DefaultEnvPrefix) + v.AllowEmptyEnv(true) + v.AutomaticEnv() + + _ = v.BindEnv("subscription_id") + _ = v.BindEnv("scanner_location") + _ = v.BindEnv("scanner_resource_group") + _ = v.BindEnv("scanner_subnet_id") + _ = v.BindEnv("scanner_public_key") + _ = v.BindEnv("scanner_vm_size") + _ = v.BindEnv("scanner_image_publisher") + _ = v.BindEnv("scanner_image_offer") + _ = v.BindEnv("scanner_image_sku") + _ = v.BindEnv("scanner_image_version") + _ = v.BindEnv("scanner_security_group") + _ = v.BindEnv("scanner_storage_account_name") + _ = v.BindEnv("scanner_storage_container_name") + + config := &Config{} + if err := v.Unmarshal(&config, viper.DecodeHook(mapstructure.TextUnmarshallerHookFunc())); err != nil { + return nil, fmt.Errorf("failed to parse provider configuration. Provider=Azure: %w", err) + } + return config, nil +} + +// nolint:cyclop +func (c Config) Validate() error { + if c.SubscriptionID == "" { + return errors.New("parameter SubscriptionID must be provided") + } + + if c.ScannerLocation == "" { + return errors.New("parameter ScannerLocation must be provided") + } + + if c.ScannerResourceGroup == "" { + return errors.New("parameter ScannerResourceGroup must be provided") + } + + if c.ScannerSubnet == "" { + return errors.New("parameter ScannerSubnet must be provided") + } + + if c.ScannerVMSize == "" { + return errors.New("parameter ScannerVMSize must be provided") + } + + if c.ScannerImagePublisher == "" { + return errors.New("parameter ScannerImagePublisher must be provided") + } + + if c.ScannerImageOffer == "" { + return errors.New("parameter ScannerImageOffer must be provided") + } + + if c.ScannerImageSKU == "" { + return errors.New("parameter ScannerImageSKU must be provided") + } + + if c.ScannerImageVersion == "" { + return errors.New("parameter ScannerImageVersion must be provided") + } + + if c.ScannerSecurityGroup == "" { + return errors.New("parameter ScannerSecurityGroup must be provided") + } + + if c.ScannerStorageAccountName == "" { + return errors.New("parameter ScannerStorageAccountName must be provided") + } + + if c.ScannerStorageContainerName == "" { + return errors.New("parameter ScannerStorageContainerName must be provided") + } + + return nil +} diff --git a/provider/v2/azure/discoverer/discoverer.go b/provider/v2/azure/discoverer/discoverer.go index 03706bb43..a936169d5 100644 --- a/provider/v2/azure/discoverer/discoverer.go +++ b/provider/v2/azure/discoverer/discoverer.go @@ -17,15 +17,142 @@ package discoverer import ( "context" + "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + + apitypes "github.com/openclarity/vmclarity/api/types" + "github.com/openclarity/vmclarity/core/log" + "github.com/openclarity/vmclarity/core/to" "github.com/openclarity/vmclarity/provider" ) -var _ provider.Discoverer = &Discoverer{} - -type Discoverer struct{} +type Discoverer struct { + VMClient *armcompute.VirtualMachinesClient + DisksClient *armcompute.DisksClient +} func (d *Discoverer) DiscoverAssets(ctx context.Context) provider.AssetDiscoverer { - // TODO implement me - panic("implement me") + assetDiscoverer := provider.NewSimpleAssetDiscoverer() + + go func() { + defer close(assetDiscoverer.OutputChan) + + // list all vms in all resourceGroups in the subscription + res := d.VMClient.NewListAllPager(nil) + for res.More() { + page, err := res.NextPage(ctx) + if err != nil { + assetDiscoverer.Error = fmt.Errorf("failed to get next page: %w", err) + return + } + ts, err := d.processVirtualMachineListIntoAssetTypes(ctx, page.VirtualMachineListResult) + if err != nil { + assetDiscoverer.Error = err + return + } + + for _, asset := range ts { + select { + case assetDiscoverer.OutputChan <- asset: + case <-ctx.Done(): + assetDiscoverer.Error = ctx.Err() + return + } + } + } + }() + + return assetDiscoverer +} + +func (d *Discoverer) processVirtualMachineListIntoAssetTypes(ctx context.Context, vmList armcompute.VirtualMachineListResult) ([]apitypes.AssetType, error) { + ret := make([]apitypes.AssetType, 0, len(vmList.Value)) + for _, vm := range vmList.Value { + info, err := getVMInfoFromVirtualMachine(vm, d.getRootVolumeInfo(ctx, vm)) + if err != nil { + return nil, fmt.Errorf("unable to convert instance to vminfo: %w", err) + } + ret = append(ret, info) + } + return ret, nil +} + +func (d *Discoverer) getRootVolumeInfo(ctx context.Context, vm *armcompute.VirtualMachine) *apitypes.RootVolume { + logger := log.GetLoggerFromContextOrDiscard(ctx) + ret := &apitypes.RootVolume{ + SizeGB: int(to.ValueOrZero(vm.Properties.StorageProfile.OSDisk.DiskSizeGB)), + Encrypted: apitypes.RootVolumeEncryptedUnknown, + } + osDiskID, err := arm.ParseResourceID(to.ValueOrZero(vm.Properties.StorageProfile.OSDisk.ManagedDisk.ID)) + if err != nil { + logger.Warnf("Failed to parse disk ID. DiskID=%v: %v", + to.ValueOrZero(vm.Properties.StorageProfile.OSDisk.ManagedDisk.ID), err) + return ret + } + osDisk, err := d.DisksClient.Get(ctx, osDiskID.ResourceGroupName, osDiskID.Name, nil) + if err != nil { + logger.Warnf("Failed to get OS disk. DiskID=%v: %v", + to.ValueOrZero(vm.Properties.StorageProfile.OSDisk.ManagedDisk.ID), err) + return ret + } + ret.Encrypted = isEncrypted(osDisk) + ret.SizeGB = int(to.ValueOrZero(osDisk.Disk.Properties.DiskSizeGB)) + + return ret +} + +func getVMInfoFromVirtualMachine(vm *armcompute.VirtualMachine, rootVol *apitypes.RootVolume) (apitypes.AssetType, error) { + assetType := apitypes.AssetType{} + err := assetType.FromVMInfo(apitypes.VMInfo{ + ObjectType: "VMInfo", + InstanceProvider: to.Ptr(apitypes.Azure), + InstanceID: *vm.ID, + Image: createImageURN(vm.Properties.StorageProfile.ImageReference), + InstanceType: *vm.Type, + LaunchTime: *vm.Properties.TimeCreated, + Location: *vm.Location, + Platform: string(*vm.Properties.StorageProfile.OSDisk.OSType), + RootVolume: *rootVol, + SecurityGroups: &[]apitypes.SecurityGroup{}, + Tags: convertTags(vm.Tags), + }) + if err != nil { + err = fmt.Errorf("failed to create AssetType from VMInfo: %w", err) + } + + return assetType, err +} + +func isEncrypted(disk armcompute.DisksClientGetResponse) apitypes.RootVolumeEncrypted { + if disk.Properties.EncryptionSettingsCollection == nil { + return apitypes.RootVolumeEncryptedNo + } + if *disk.Properties.EncryptionSettingsCollection.Enabled { + return apitypes.RootVolumeEncryptedYes + } + + return apitypes.RootVolumeEncryptedNo +} + +func convertTags(tags map[string]*string) *[]apitypes.Tag { + ret := make([]apitypes.Tag, 0, len(tags)) + for key, val := range tags { + ret = append(ret, apitypes.Tag{ + Key: key, + Value: *val, + }) + } + return &ret +} + +// https://learn.microsoft.com/en-us/azure/virtual-machines/linux/tutorial-manage-vm#understand-vm-images +func createImageURN(reference *armcompute.ImageReference) string { + // ImageReference is required only when using platform images, marketplace images, or + // virtual machine images, but is not used in other creation operations (like managed disks). + if reference == nil { + return "" + } + return *reference.Publisher + "/" + *reference.Offer + "/" + *reference.SKU + "/" + *reference.Version } diff --git a/provider/v2/azure/provider.go b/provider/v2/azure/provider.go index 455d8a2ae..99154bf3f 100644 --- a/provider/v2/azure/provider.go +++ b/provider/v2/azure/provider.go @@ -17,8 +17,13 @@ package azure import ( "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" apitypes "github.com/openclarity/vmclarity/api/types" + "github.com/openclarity/vmclarity/provider/v2/azure/common" "github.com/openclarity/vmclarity/provider/v2/azure/discoverer" "github.com/openclarity/vmclarity/provider/v2/azure/estimator" "github.com/openclarity/vmclarity/provider/v2/azure/scanner" @@ -35,9 +40,32 @@ func (p *Provider) Kind() apitypes.CloudProvider { } func New(_ context.Context) (*Provider, error) { + config, err := common.NewConfig() + if err != nil { + return nil, fmt.Errorf("failed to load configuration: %w", err) + } + + err = config.Validate() + if err != nil { + return nil, fmt.Errorf("failed to validate configuration: %w", err) + } + + cred, err := azidentity.NewManagedIdentityCredential(nil) + if err != nil { + return nil, fmt.Errorf("failed create managed identity credential: %w", err) + } + + computeClientFactory, err := armcompute.NewClientFactory(config.SubscriptionID, cred, nil) + if err != nil { + return nil, fmt.Errorf("failed to create compute client factory: %w", err) + } + return &Provider{ - Discoverer: &discoverer.Discoverer{}, - Scanner: &scanner.Scanner{}, - Estimator: &estimator.Estimator{}, + Discoverer: &discoverer.Discoverer{ + VMClient: computeClientFactory.NewVirtualMachinesClient(), + DisksClient: computeClientFactory.NewDisksClient(), + }, + Scanner: &scanner.Scanner{}, + Estimator: &estimator.Estimator{}, }, nil } From 0680677a6b8a12bdc728901d14eafc2e2dea3190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Thu, 22 Feb 2024 16:50:23 +0100 Subject: [PATCH 4/9] refactor: RunAssetScan method in Azure providerv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/common/common.go | 51 ++++++ provider/v2/azure/provider.go | 16 +- provider/v2/azure/scanner/blob.go | 108 +++++++++++ provider/v2/azure/scanner/networkInterface.go | 81 +++++++++ provider/v2/azure/scanner/scanner.go | 92 +++++++++- provider/v2/azure/scanner/scannerVm.go | 171 ++++++++++++++++++ provider/v2/azure/scanner/snapshot.go | 70 +++++++ provider/v2/azure/scanner/targetDisk.go | 115 ++++++++++++ 8 files changed, 698 insertions(+), 6 deletions(-) create mode 100644 provider/v2/azure/common/common.go create mode 100644 provider/v2/azure/scanner/blob.go create mode 100644 provider/v2/azure/scanner/networkInterface.go create mode 100644 provider/v2/azure/scanner/scannerVm.go create mode 100644 provider/v2/azure/scanner/snapshot.go create mode 100644 provider/v2/azure/scanner/targetDisk.go diff --git a/provider/v2/azure/common/common.go b/provider/v2/azure/common/common.go new file mode 100644 index 000000000..8624a83b4 --- /dev/null +++ b/provider/v2/azure/common/common.go @@ -0,0 +1,51 @@ +// 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 common + +import ( + "errors" + "fmt" + "net/http" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + + "github.com/openclarity/vmclarity/provider" +) + +func HandleAzureRequestError(err error, actionTmpl string, parts ...interface{}) (bool, error) { + action := fmt.Sprintf(actionTmpl, parts...) + + var respError *azcore.ResponseError + if !errors.As(err, &respError) { + // Error should be an azcore.ResponseError otherwise something + // bad has happened in the client. + return false, provider.FatalErrorf("unexpected error from azure while %s: %w", action, err) + } + + sc := respError.StatusCode + switch { + case sc >= 400 && sc < 500: + // Client errors (BadRequest/Unauthorized/etc.) are Fatal. We + // also return true to indicate we have NotFound which is a + // special case in a lot of processing. + return sc == http.StatusNotFound, provider.FatalErrorf("error from azure while %s: %w", action, err) + default: + // Everything else is a normal error which can be + // logged as a failure and then the reconciler will try + // again on the next loop. + return false, fmt.Errorf("error from azure while %s: %w", action, err) + } +} diff --git a/provider/v2/azure/provider.go b/provider/v2/azure/provider.go index 99154bf3f..944223135 100644 --- a/provider/v2/azure/provider.go +++ b/provider/v2/azure/provider.go @@ -21,6 +21,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5" apitypes "github.com/openclarity/vmclarity/api/types" "github.com/openclarity/vmclarity/provider/v2/azure/common" @@ -55,6 +56,11 @@ func New(_ context.Context) (*Provider, error) { return nil, fmt.Errorf("failed create managed identity credential: %w", err) } + networkClientFactory, err := armnetwork.NewClientFactory(config.SubscriptionID, cred, nil) + if err != nil { + return nil, fmt.Errorf("failed to create network client factory: %w", err) + } + computeClientFactory, err := armcompute.NewClientFactory(config.SubscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create compute client factory: %w", err) @@ -65,7 +71,15 @@ func New(_ context.Context) (*Provider, error) { VMClient: computeClientFactory.NewVirtualMachinesClient(), DisksClient: computeClientFactory.NewDisksClient(), }, - Scanner: &scanner.Scanner{}, + Scanner: &scanner.Scanner{ + Cred: cred, + VMClient: computeClientFactory.NewVirtualMachinesClient(), + SnapshotsClient: computeClientFactory.NewSnapshotsClient(), + DisksClient: computeClientFactory.NewDisksClient(), + InterfacesClient: networkClientFactory.NewInterfacesClient(), + + Config: config, + }, Estimator: &estimator.Estimator{}, }, nil } diff --git a/provider/v2/azure/scanner/blob.go b/provider/v2/azure/scanner/blob.go new file mode 100644 index 000000000..cd8045494 --- /dev/null +++ b/provider/v2/azure/scanner/blob.go @@ -0,0 +1,108 @@ +// 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 scanner + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" + + "github.com/openclarity/vmclarity/core/to" + "github.com/openclarity/vmclarity/provider" + "github.com/openclarity/vmclarity/provider/v2/azure/common" +) + +var ( + estimatedBlobCopyTime = 2 * time.Minute + snapshotSASAccessSeconds = 3600 +) + +func blobNameFromJobConfig(config *provider.ScanJobConfig) string { + return config.AssetScanID + ".vhd" +} + +func (s *Scanner) blobURLFromBlobName(blobName string) string { + return fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", s.Config.ScannerStorageAccountName, s.Config.ScannerStorageContainerName, blobName) +} + +func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.ScanJobConfig, snapshot armcompute.Snapshot) (string, error) { + blobName := blobNameFromJobConfig(config) + blobURL := s.blobURLFromBlobName(blobName) + blobClient, err := blob.NewClient(blobURL, s.Cred, nil) + if err != nil { + return blobURL, provider.FatalErrorf("failed to init blob client: %w", err) + } + + getMetadata, err := blobClient.GetProperties(ctx, nil) + if err == nil { + copyStatus := *getMetadata.CopyStatus + if copyStatus != blob.CopyStatusTypeSuccess { + log.Print("blob is still copying, status is ", copyStatus) + return blobURL, provider.RetryableErrorf(estimatedBlobCopyTime, "blob is still copying") + } + + revokepoller, err := s.SnapshotsClient.BeginRevokeAccess(ctx, s.Config.ScannerResourceGroup, *snapshot.Name, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "revoking SAS access for snapshot %s", *snapshot.Name) + return blobURL, err + } + _, err = revokepoller.PollUntilDone(ctx, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "waiting for SAS access to be revoked for snapshot %s", *snapshot.Name) + return blobURL, err + } + + return blobURL, nil + } + + notFound, err := common.HandleAzureRequestError(err, "getting blob %s", blobName) + if !notFound { + return blobURL, err + } + + // NOTE(sambetts) Granting SAS access to a snapshot must be done + // atomically with starting the CopyFromUrl Operation because + // GrantAccess only provides the URL once, and we don't want to store + // it. + poller, err := s.SnapshotsClient.BeginGrantAccess(ctx, s.Config.ScannerResourceGroup, *snapshot.Name, armcompute.GrantAccessData{ + Access: to.Ptr(armcompute.AccessLevelRead), + DurationInSeconds: to.Ptr[int32](int32(snapshotSASAccessSeconds)), + }, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "granting SAS access to snapshot %s", *snapshot.Name) + return blobURL, err + } + + res, err := poller.PollUntilDone(ctx, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "waiting for SAS access to snapshot %s be granted", *snapshot.Name) + return blobURL, err + } + + accessURL := *res.AccessURI.AccessSAS + + _, err = blobClient.StartCopyFromURL(ctx, accessURL, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "starting copy from URL operation for blob %s", blobName) + return blobURL, err + } + + return blobURL, provider.RetryableErrorf(estimatedBlobCopyTime, "blob copy from url started") +} diff --git a/provider/v2/azure/scanner/networkInterface.go b/provider/v2/azure/scanner/networkInterface.go new file mode 100644 index 000000000..dcc696081 --- /dev/null +++ b/provider/v2/azure/scanner/networkInterface.go @@ -0,0 +1,81 @@ +// 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 scanner + +import ( + "context" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5" + + "github.com/openclarity/vmclarity/core/to" + "github.com/openclarity/vmclarity/provider" + "github.com/openclarity/vmclarity/provider/v2/azure/common" +) + +var ( + NetworkInterfaceEstimateProvisionTime = 10 * time.Second +) + +func networkInterfaceNameFromJobConfig(config *provider.ScanJobConfig) string { + return "scanner-nic-" + config.AssetScanID +} + +func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.ScanJobConfig) (armnetwork.Interface, error) { + nicName := networkInterfaceNameFromJobConfig(config) + + nicResp, err := s.InterfacesClient.Get(ctx, s.Config.ScannerResourceGroup, nicName, nil) + if err == nil { + if *nicResp.Interface.Properties.ProvisioningState != provisioningStateSucceeded { + return nicResp.Interface, provider.RetryableErrorf(NetworkInterfaceEstimateProvisionTime, "interface is not ready yet, provisioning state: %s", *nicResp.Interface.Properties.ProvisioningState) + } + + return nicResp.Interface, nil + } + + notFound, err := common.HandleAzureRequestError(err, "getting interface %s", nicName) + if !notFound { + return armnetwork.Interface{}, err + } + + parameters := armnetwork.Interface{ + Location: to.Ptr(s.Config.ScannerLocation), + Properties: &armnetwork.InterfacePropertiesFormat{ + IPConfigurations: []*armnetwork.InterfaceIPConfiguration{ + { + Name: to.Ptr(nicName + "-ipconfig"), + Properties: &armnetwork.InterfaceIPConfigurationPropertiesFormat{ + PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic), + Subnet: &armnetwork.Subnet{ + ID: to.Ptr(s.Config.ScannerSubnet), + }, + }, + }, + }, + NetworkSecurityGroup: &armnetwork.SecurityGroup{ + ID: to.Ptr(s.Config.ScannerSecurityGroup), + }, + }, + } + + _, err = s.InterfacesClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, nicName, parameters, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "creating interface %s", nicName) + return armnetwork.Interface{}, err + } + + return armnetwork.Interface{}, provider.RetryableErrorf(NetworkInterfaceEstimateProvisionTime, "interface creating") +} diff --git a/provider/v2/azure/scanner/scanner.go b/provider/v2/azure/scanner/scanner.go index 9a6064884..46d5017c4 100644 --- a/provider/v2/azure/scanner/scanner.go +++ b/provider/v2/azure/scanner/scanner.go @@ -17,20 +17,102 @@ package scanner import ( "context" + "fmt" + "strings" + + "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/common" ) -var _ provider.Scanner = &Scanner{} +const ( + provisioningStateSucceeded = "Succeeded" + instanceIDPartsLength = 9 + resourceGroupPartIdx = 4 + vmNamePartIdx = 8 +) -type Scanner struct{} +type Scanner struct { + Cred azcore.TokenCredential + VMClient *armcompute.VirtualMachinesClient + SnapshotsClient *armcompute.SnapshotsClient + DisksClient *armcompute.DisksClient + InterfacesClient *armnetwork.InterfacesClient -func (s *Scanner) RunAssetScan(ctx context.Context, t *provider.ScanJobConfig) error { - // TODO implement me - panic("implement me") + Config *common.Config +} + +// nolint:cyclop +func (s *Scanner) RunAssetScan(ctx context.Context, config *provider.ScanJobConfig) 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 + } + + assetVM, err := s.VMClient.Get(ctx, resourceGroup, vmName, nil) + if err != nil { + _, err = common.HandleAzureRequestError(err, "getting asset virtual machine %s", vmName) + return err + } + + snapshot, err := s.ensureSnapshotForVMRootVolume(ctx, config, assetVM.VirtualMachine) + if err != nil { + return fmt.Errorf("failed to ensure snapshot for vm root volume: %w", err) + } + + var disk armcompute.Disk + if *assetVM.Location == s.Config.ScannerLocation { + disk, err = s.ensureManagedDiskFromSnapshot(ctx, config, snapshot) + if err != nil { + return fmt.Errorf("failed to ensure managed disk created from snapshot: %w", err) + } + } else { + disk, err = s.ensureManagedDiskFromSnapshotInDifferentRegion(ctx, config, snapshot) + if err != nil { + return fmt.Errorf("failed to ensure managed disk from snapshot in different region: %w", err) + } + } + + networkInterface, err := s.ensureNetworkInterface(ctx, config) + if err != nil { + return fmt.Errorf("failed to ensure scanner network interface: %w", err) + } + + scannerVM, err := s.ensureScannerVirtualMachine(ctx, config, networkInterface) + if err != nil { + return fmt.Errorf("failed to ensure scanner virtual machine: %w", err) + } + + err = s.ensureDiskAttachedToScannerVM(ctx, scannerVM, disk) + if err != nil { + return fmt.Errorf("failed to ensure asset disk is attached to virtual machine: %w", err) + } + + return nil } func (s *Scanner) RemoveAssetScan(ctx context.Context, t *provider.ScanJobConfig) error { // TODO implement me panic("implement me") } + +// 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 +} diff --git a/provider/v2/azure/scanner/scannerVm.go b/provider/v2/azure/scanner/scannerVm.go new file mode 100644 index 000000000..ef35dee54 --- /dev/null +++ b/provider/v2/azure/scanner/scannerVm.go @@ -0,0 +1,171 @@ +// 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 scanner + +import ( + "context" + "encoding/base64" + "fmt" + "time" + + "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/core/to" + "github.com/openclarity/vmclarity/provider" + "github.com/openclarity/vmclarity/provider/cloudinit" + "github.com/openclarity/vmclarity/provider/v2/azure/common" +) + +var ( + VMCreateEstimateProvisionTime = 2 * time.Minute + VMDiskAttachEstimateTime = 2 * time.Minute +) + +func scannerVMNameFromJobConfig(config *provider.ScanJobConfig) string { + return "vmclarity-scanner-" + config.AssetScanID +} + +func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provider.ScanJobConfig, networkInterface armnetwork.Interface) (armcompute.VirtualMachine, error) { + vmName := scannerVMNameFromJobConfig(config) + + vmResp, err := s.VMClient.Get(ctx, s.Config.ScannerResourceGroup, vmName, nil) + if err == nil { + if *vmResp.VirtualMachine.Properties.ProvisioningState != provisioningStateSucceeded { + return vmResp.VirtualMachine, provider.RetryableErrorf(VMCreateEstimateProvisionTime, "VM is not ready yet, provisioning state: %s", *vmResp.VirtualMachine.Properties.ProvisioningState) + } + return vmResp.VirtualMachine, nil + } + + notFound, err := common.HandleAzureRequestError(err, "getting scanner virtual machine: %s", vmName) + if !notFound { + return armcompute.VirtualMachine{}, err + } + + userData, err := cloudinit.New(config) + if err != nil { + return armcompute.VirtualMachine{}, fmt.Errorf("failed to generate cloud-init: %w", err) + } + userDataBase64 := base64.StdEncoding.EncodeToString([]byte(userData)) + + parameters := armcompute.VirtualMachine{ + Location: to.Ptr(s.Config.ScannerLocation), + Identity: &armcompute.VirtualMachineIdentity{ + // Scanners don't need access to Azure so no need for an Identity + Type: to.Ptr(armcompute.ResourceIdentityTypeNone), + }, + Properties: &armcompute.VirtualMachineProperties{ + HardwareProfile: &armcompute.HardwareProfile{ + VMSize: to.Ptr(armcompute.VirtualMachineSizeTypes(s.Config.ScannerVMSize)), + }, + StorageProfile: &armcompute.StorageProfile{ + ImageReference: &armcompute.ImageReference{ + Publisher: to.Ptr(s.Config.ScannerImagePublisher), + SKU: to.Ptr(s.Config.ScannerImageSKU), + Version: to.Ptr(s.Config.ScannerImageVersion), + Offer: to.Ptr(s.Config.ScannerImageOffer), + }, + OSDisk: &armcompute.OSDisk{ + Name: to.Ptr(vmName + "-rootvolume"), + CreateOption: to.Ptr(armcompute.DiskCreateOptionTypesFromImage), + // Delete disk on VM delete + DeleteOption: to.Ptr(armcompute.DiskDeleteOptionTypesDelete), + Caching: to.Ptr(armcompute.CachingTypesReadWrite), + ManagedDisk: &armcompute.ManagedDiskParameters{ + // OSDisk type Standard/Premium HDD/SSD + StorageAccountType: to.Ptr(armcompute.StorageAccountTypesStandardLRS), + }, + // DiskSizeGB: to.Ptr[int32](100), // default 127G + }, + }, + OSProfile: &armcompute.OSProfile{ // use username/password + ComputerName: to.Ptr(vmName), + AdminUsername: to.Ptr("vmclarity"), + LinuxConfiguration: &armcompute.LinuxConfiguration{ + DisablePasswordAuthentication: to.Ptr(true), + }, + }, + NetworkProfile: &armcompute.NetworkProfile{ + NetworkInterfaces: []*armcompute.NetworkInterfaceReference{ + { + ID: networkInterface.ID, + }, + }, + }, + UserData: &userDataBase64, + }, + } + + if s.Config.ScannerPublicKey != "" { + parameters.Properties.OSProfile.LinuxConfiguration.SSH = &armcompute.SSHConfiguration{ + PublicKeys: []*armcompute.SSHPublicKey{ + { + Path: to.Ptr(fmt.Sprintf("/home/%s/.ssh/authorized_keys", "vmclarity")), + KeyData: to.Ptr(string(s.Config.ScannerPublicKey)), + }, + }, + } + } + + _, err = s.VMClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, vmName, parameters, nil) + if err != nil { + _, err = common.HandleAzureRequestError(err, "creating virtual machine") + return armcompute.VirtualMachine{}, err + } + + return armcompute.VirtualMachine{}, provider.RetryableErrorf(VMCreateEstimateProvisionTime, "vm created") +} + +func (s *Scanner) ensureDiskAttachedToScannerVM(ctx context.Context, vm armcompute.VirtualMachine, disk armcompute.Disk) error { + var vmAttachedToDisk bool + for _, dataDisk := range vm.Properties.StorageProfile.DataDisks { + if dataDisk.ManagedDisk.ID == disk.ID { + vmAttachedToDisk = true + break + } + } + + if !vmAttachedToDisk { + vm.Properties.StorageProfile.DataDisks = []*armcompute.DataDisk{ + { + CreateOption: to.Ptr(armcompute.DiskCreateOptionTypesAttach), + Lun: to.Ptr[int32](0), + ManagedDisk: &armcompute.ManagedDiskParameters{ + ID: disk.ID, + }, + Name: disk.Name, + }, + } + + _, err := s.VMClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, *vm.Name, vm, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "attaching disk %s to VM %s", *disk.Name, *vm.Name) + return err + } + } + + diskResp, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, *disk.Name, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "getting disk %s", *disk.Name) + return err + } + + if *diskResp.Disk.Properties.DiskState != armcompute.DiskStateAttached { + return provider.RetryableErrorf(VMDiskAttachEstimateTime, "volume is not yet attached, disk is in state: %v", *diskResp.Disk.Properties.DiskState) + } + + return nil +} diff --git a/provider/v2/azure/scanner/snapshot.go b/provider/v2/azure/scanner/snapshot.go new file mode 100644 index 000000000..0a2cbac29 --- /dev/null +++ b/provider/v2/azure/scanner/snapshot.go @@ -0,0 +1,70 @@ +// 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 scanner + +import ( + "context" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + + "github.com/openclarity/vmclarity/core/to" + "github.com/openclarity/vmclarity/provider" + "github.com/openclarity/vmclarity/provider/v2/azure/common" +) + +var ( + SnapshotCreateEstimateProvisionTime = 2 * time.Minute +) + +func snapshotNameFromJobConfig(config *provider.ScanJobConfig) string { + return "snapshot-" + config.AssetScanID +} + +func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *provider.ScanJobConfig, vm armcompute.VirtualMachine) (armcompute.Snapshot, error) { + snapshotName := snapshotNameFromJobConfig(config) + + snapshotRes, err := s.SnapshotsClient.Get(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) + if err == nil { + if *snapshotRes.Properties.ProvisioningState != provisioningStateSucceeded { + return snapshotRes.Snapshot, provider.RetryableErrorf(SnapshotCreateEstimateProvisionTime, "snapshot is not ready yet") + } + + // Everything is good, the snapshot exists and is provisioned successfully + return snapshotRes.Snapshot, nil + } + + notFound, err := common.HandleAzureRequestError(err, "getting snapshot %s", snapshotName) + if !notFound { + return armcompute.Snapshot{}, err + } + + _, err = s.SnapshotsClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, snapshotName, armcompute.Snapshot{ + Location: vm.Location, + Properties: &armcompute.SnapshotProperties{ + CreationData: &armcompute.CreationData{ + CreateOption: to.Ptr(armcompute.DiskCreateOptionCopy), + SourceResourceID: vm.Properties.StorageProfile.OSDisk.ManagedDisk.ID, + }, + }, + }, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "creating snapshot %s", snapshotName) + return armcompute.Snapshot{}, err + } + + return armcompute.Snapshot{}, provider.RetryableErrorf(SnapshotCreateEstimateProvisionTime, "snapshot creating") +} diff --git a/provider/v2/azure/scanner/targetDisk.go b/provider/v2/azure/scanner/targetDisk.go new file mode 100644 index 000000000..eff31ae27 --- /dev/null +++ b/provider/v2/azure/scanner/targetDisk.go @@ -0,0 +1,115 @@ +// 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 scanner + +import ( + "context" + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + + "github.com/openclarity/vmclarity/core/to" + "github.com/openclarity/vmclarity/provider" + "github.com/openclarity/vmclarity/provider/v2/azure/common" +) + +var ( + DiskEstimateProvisionTime = 2 * time.Minute +) + +func volumeNameFromJobConfig(config *provider.ScanJobConfig) string { + return "targetvolume-" + config.AssetScanID +} + +func (s *Scanner) ensureManagedDiskFromSnapshot(ctx context.Context, config *provider.ScanJobConfig, snapshot armcompute.Snapshot) (armcompute.Disk, error) { + volumeName := volumeNameFromJobConfig(config) + + volumeRes, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + if err == nil { + if *volumeRes.Disk.Properties.ProvisioningState != provisioningStateSucceeded { + return volumeRes.Disk, provider.RetryableErrorf(DiskEstimateProvisionTime, "volume is not ready yet, provisioning state: %s", *volumeRes.Disk.Properties.ProvisioningState) + } + + return volumeRes.Disk, nil + } + + notFound, err := common.HandleAzureRequestError(err, "getting volume %s", volumeName) + if !notFound { + return armcompute.Disk{}, err + } + + _, err = s.DisksClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, volumeName, armcompute.Disk{ + Location: to.Ptr(s.Config.ScannerLocation), + SKU: &armcompute.DiskSKU{ + Name: to.Ptr(armcompute.DiskStorageAccountTypesStandardSSDLRS), + }, + Properties: &armcompute.DiskProperties{ + CreationData: &armcompute.CreationData{ + CreateOption: to.Ptr(armcompute.DiskCreateOptionCopy), + SourceResourceID: snapshot.ID, + }, + }, + }, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "creating disk %s", volumeName) + return armcompute.Disk{}, err + } + + return armcompute.Disk{}, provider.RetryableErrorf(DiskEstimateProvisionTime, "disk creating") +} + +func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Context, config *provider.ScanJobConfig, snapshot armcompute.Snapshot) (armcompute.Disk, error) { + blobURL, err := s.ensureBlobFromSnapshot(ctx, config, snapshot) + if err != nil { + return armcompute.Disk{}, fmt.Errorf("failed to ensure blob from snapshot: %w", err) + } + + volumeName := volumeNameFromJobConfig(config) + + volumeRes, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + if err == nil { + if *volumeRes.Disk.Properties.ProvisioningState != provisioningStateSucceeded { + return volumeRes.Disk, provider.RetryableErrorf(DiskEstimateProvisionTime, "volume is not ready yet, provisioning state: %s", *volumeRes.Disk.Properties.ProvisioningState) + } + + return volumeRes.Disk, nil + } + + notFound, err := common.HandleAzureRequestError(err, "getting volume %s", volumeName) + if !notFound { + return armcompute.Disk{}, err + } + + _, err = s.DisksClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, volumeName, armcompute.Disk{ + Location: to.Ptr(s.Config.ScannerLocation), + SKU: &armcompute.DiskSKU{ + Name: to.Ptr(armcompute.DiskStorageAccountTypesStandardSSDLRS), + }, + Properties: &armcompute.DiskProperties{ + CreationData: &armcompute.CreationData{ + CreateOption: to.Ptr(armcompute.DiskCreateOptionImport), + SourceURI: to.Ptr(blobURL), + StorageAccountID: to.Ptr(fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", s.Config.SubscriptionID, s.Config.ScannerResourceGroup, s.Config.ScannerStorageAccountName)), + }, + }, + }, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "creating disk %s", volumeName) + return armcompute.Disk{}, err + } + return armcompute.Disk{}, provider.RetryableErrorf(DiskEstimateProvisionTime, "disk creating") +} From 0b6f57ed9f9e820e739bc00c1dd7709851af67ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Thu, 22 Feb 2024 17:29:35 +0100 Subject: [PATCH 5/9] refactor: RemoveAssetScan method in Azure providerv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/common/common.go | 22 ++++++++++ provider/v2/azure/scanner/blob.go | 40 ++++++++++++++++++- provider/v2/azure/scanner/networkInterface.go | 18 +++++++++ provider/v2/azure/scanner/scanner.go | 30 ++++++++++++-- provider/v2/azure/scanner/scannerVm.go | 18 +++++++++ provider/v2/azure/scanner/snapshot.go | 18 +++++++++ provider/v2/azure/scanner/targetDisk.go | 18 +++++++++ 7 files changed, 160 insertions(+), 4 deletions(-) diff --git a/provider/v2/azure/common/common.go b/provider/v2/azure/common/common.go index 8624a83b4..d459910f1 100644 --- a/provider/v2/azure/common/common.go +++ b/provider/v2/azure/common/common.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "net/http" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" @@ -49,3 +50,24 @@ func HandleAzureRequestError(err error, actionTmpl string, parts ...interface{}) return false, fmt.Errorf("error from azure while %s: %w", action, err) } } + +func EnsureDeleted(resourceType string, getFunc func() error, deleteFunc func() error, estimateTime time.Duration) error { + err := getFunc() + if err != nil { + notFound, err := HandleAzureRequestError(err, "getting %s", resourceType) + // NotFound means that the resource has been deleted + // successfully, all other errors are raised. + if notFound { + return nil + } + return err + } + + err = deleteFunc() + if err != nil { + _, err := HandleAzureRequestError(err, "deleting %s", resourceType) + return err + } + + return provider.RetryableErrorf(estimateTime, "%s delete issued", resourceType) +} diff --git a/provider/v2/azure/scanner/blob.go b/provider/v2/azure/scanner/blob.go index cd8045494..b65e9cd15 100644 --- a/provider/v2/azure/scanner/blob.go +++ b/provider/v2/azure/scanner/blob.go @@ -30,7 +30,9 @@ import ( ) var ( - estimatedBlobCopyTime = 2 * time.Minute + estimatedBlobCopyTime = 2 * time.Minute + estimatedBlobAbortTime = 2 * time.Minute + estimatedBlobDeleteTime = 2 * time.Minute snapshotSASAccessSeconds = 3600 ) @@ -106,3 +108,39 @@ func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.S return blobURL, provider.RetryableErrorf(estimatedBlobCopyTime, "blob copy from url started") } + +func (s *Scanner) ensureBlobDeleted(ctx context.Context, config *provider.ScanJobConfig) error { + blobName := blobNameFromJobConfig(config) + blobURL := s.blobURLFromBlobName(blobName) + blobClient, err := blob.NewClient(blobURL, s.Cred, nil) + if err != nil { + return provider.FatalErrorf("failed to init blob client: %w", err) + } + + getMetadata, err := blobClient.GetProperties(ctx, nil) + if err != nil { + notFound, err := common.HandleAzureRequestError(err, "getting blob %s", blobName) + if notFound { + return nil + } + return err + } + + copyStatus := *getMetadata.CopyStatus + if copyStatus == blob.CopyStatusTypePending { + _, err = blobClient.AbortCopyFromURL(ctx, *getMetadata.CopyID, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "aborting copy from url for blob %s", blobName) + return err + } + return provider.RetryableErrorf(estimatedBlobAbortTime, "blob copy aborting") + } + + _, err = blobClient.Delete(ctx, nil) + if err != nil { + _, err := common.HandleAzureRequestError(err, "deleting blob %s", blobName) + return err + } + + return provider.RetryableErrorf(estimatedBlobDeleteTime, "blob %s delete started", blobName) +} diff --git a/provider/v2/azure/scanner/networkInterface.go b/provider/v2/azure/scanner/networkInterface.go index dcc696081..ee5bb97a6 100644 --- a/provider/v2/azure/scanner/networkInterface.go +++ b/provider/v2/azure/scanner/networkInterface.go @@ -28,6 +28,7 @@ import ( var ( NetworkInterfaceEstimateProvisionTime = 10 * time.Second + NetworkInterfaceDeleteEstimateTime = 10 * time.Second ) func networkInterfaceNameFromJobConfig(config *provider.ScanJobConfig) string { @@ -79,3 +80,20 @@ func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.S return armnetwork.Interface{}, provider.RetryableErrorf(NetworkInterfaceEstimateProvisionTime, "interface creating") } + +func (s *Scanner) ensureNetworkInterfaceDeleted(ctx context.Context, config *provider.ScanJobConfig) error { + nicName := networkInterfaceNameFromJobConfig(config) + + return common.EnsureDeleted( + "interface", + func() error { + _, err := s.InterfacesClient.Get(ctx, s.Config.ScannerResourceGroup, nicName, nil) + return err // nolint: wrapcheck + }, + func() error { + _, err := s.InterfacesClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, nicName, nil) + return err // nolint: wrapcheck + }, + NetworkInterfaceDeleteEstimateTime, + ) +} diff --git a/provider/v2/azure/scanner/scanner.go b/provider/v2/azure/scanner/scanner.go index 46d5017c4..c90aa7cf3 100644 --- a/provider/v2/azure/scanner/scanner.go +++ b/provider/v2/azure/scanner/scanner.go @@ -99,9 +99,33 @@ func (s *Scanner) RunAssetScan(ctx context.Context, config *provider.ScanJobConf return nil } -func (s *Scanner) RemoveAssetScan(ctx context.Context, t *provider.ScanJobConfig) error { - // TODO implement me - panic("implement me") +func (s *Scanner) RemoveAssetScan(ctx context.Context, config *provider.ScanJobConfig) error { + err := s.ensureScannerVirtualMachineDeleted(ctx, config) + if err != nil { + return fmt.Errorf("failed to ensure scanner virtual machine deleted: %w", err) + } + + err = s.ensureNetworkInterfaceDeleted(ctx, config) + if err != nil { + return fmt.Errorf("failed to ensure network interface deleted: %w", err) + } + + err = s.ensureTargetDiskDeleted(ctx, config) + if err != nil { + return fmt.Errorf("failed to ensure asset disk deleted: %w", err) + } + + err = s.ensureBlobDeleted(ctx, config) + if err != nil { + return fmt.Errorf("failed to ensure snapshot copy blob deleted: %w", err) + } + + err = s.ensureSnapshotDeleted(ctx, config) + if err != nil { + return fmt.Errorf("failed to ensure snapshot deleted: %w", err) + } + + return nil } // Example Instance ID: diff --git a/provider/v2/azure/scanner/scannerVm.go b/provider/v2/azure/scanner/scannerVm.go index ef35dee54..9ff1937c8 100644 --- a/provider/v2/azure/scanner/scannerVm.go +++ b/provider/v2/azure/scanner/scannerVm.go @@ -33,6 +33,7 @@ import ( var ( VMCreateEstimateProvisionTime = 2 * time.Minute VMDiskAttachEstimateTime = 2 * time.Minute + VMDeleteEstimateTime = 2 * time.Minute ) func scannerVMNameFromJobConfig(config *provider.ScanJobConfig) string { @@ -129,6 +130,23 @@ func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provi return armcompute.VirtualMachine{}, provider.RetryableErrorf(VMCreateEstimateProvisionTime, "vm created") } +func (s *Scanner) ensureScannerVirtualMachineDeleted(ctx context.Context, config *provider.ScanJobConfig) error { + vmName := scannerVMNameFromJobConfig(config) + + return common.EnsureDeleted( + "virtual machine", + func() error { + _, err := s.VMClient.Get(ctx, s.Config.ScannerResourceGroup, vmName, nil) + return err // nolint: wrapcheck + }, + func() error { + _, err := s.VMClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, vmName, nil) + return err // nolint: wrapcheck + }, + VMDeleteEstimateTime, + ) +} + func (s *Scanner) ensureDiskAttachedToScannerVM(ctx context.Context, vm armcompute.VirtualMachine, disk armcompute.Disk) error { var vmAttachedToDisk bool for _, dataDisk := range vm.Properties.StorageProfile.DataDisks { diff --git a/provider/v2/azure/scanner/snapshot.go b/provider/v2/azure/scanner/snapshot.go index 0a2cbac29..a330bd5d0 100644 --- a/provider/v2/azure/scanner/snapshot.go +++ b/provider/v2/azure/scanner/snapshot.go @@ -28,6 +28,7 @@ import ( var ( SnapshotCreateEstimateProvisionTime = 2 * time.Minute + SnapshotDeleteEstimateTime = 2 * time.Minute ) func snapshotNameFromJobConfig(config *provider.ScanJobConfig) string { @@ -68,3 +69,20 @@ func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *pro return armcompute.Snapshot{}, provider.RetryableErrorf(SnapshotCreateEstimateProvisionTime, "snapshot creating") } + +func (s *Scanner) ensureSnapshotDeleted(ctx context.Context, config *provider.ScanJobConfig) error { + snapshotName := snapshotNameFromJobConfig(config) + + return common.EnsureDeleted( + "snapshot", + func() error { + _, err := s.SnapshotsClient.Get(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) + return err // nolint: wrapcheck + }, + func() error { + _, err := s.SnapshotsClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) + return err // nolint: wrapcheck + }, + SnapshotDeleteEstimateTime, + ) +} diff --git a/provider/v2/azure/scanner/targetDisk.go b/provider/v2/azure/scanner/targetDisk.go index eff31ae27..c49412c14 100644 --- a/provider/v2/azure/scanner/targetDisk.go +++ b/provider/v2/azure/scanner/targetDisk.go @@ -29,6 +29,7 @@ import ( var ( DiskEstimateProvisionTime = 2 * time.Minute + DiskDeleteEstimateTime = 2 * time.Minute ) func volumeNameFromJobConfig(config *provider.ScanJobConfig) string { @@ -113,3 +114,20 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con } return armcompute.Disk{}, provider.RetryableErrorf(DiskEstimateProvisionTime, "disk creating") } + +func (s *Scanner) ensureTargetDiskDeleted(ctx context.Context, config *provider.ScanJobConfig) error { + volumeName := volumeNameFromJobConfig(config) + + return common.EnsureDeleted( + "target disk", + func() error { + _, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + return err // nolint: wrapcheck + }, + func() error { + _, err := s.DisksClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + return err // nolint: wrapcheck + }, + DiskDeleteEstimateTime, + ) +} From 316d97205c16b40590d5d412f283835e1e4a162d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Fri, 23 Feb 2024 10:50:42 +0100 Subject: [PATCH 6/9] refactor: move tests to Azure providerv2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- .../v2/azure/discoverer/discoverer_test.go | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 provider/v2/azure/discoverer/discoverer_test.go diff --git a/provider/v2/azure/discoverer/discoverer_test.go b/provider/v2/azure/discoverer/discoverer_test.go new file mode 100644 index 000000000..27498f615 --- /dev/null +++ b/provider/v2/azure/discoverer/discoverer_test.go @@ -0,0 +1,72 @@ +// 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 discoverer + +import ( + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + + apitypes "github.com/openclarity/vmclarity/api/types" + "github.com/openclarity/vmclarity/core/to" +) + +func Test_isEncrypted(t *testing.T) { + type args struct { + disk armcompute.DisksClientGetResponse + } + tests := []struct { + name string + args args + want apitypes.RootVolumeEncrypted + }{ + { + name: "encrypted", + args: args{ + disk: armcompute.DisksClientGetResponse{ + Disk: armcompute.Disk{ + Properties: &armcompute.DiskProperties{ + EncryptionSettingsCollection: &armcompute.EncryptionSettingsCollection{ + Enabled: to.Ptr(true), + }, + }, + }, + }, + }, + want: apitypes.RootVolumeEncryptedYes, + }, + { + name: "not encrypted", + args: args{ + disk: armcompute.DisksClientGetResponse{ + Disk: armcompute.Disk{ + Properties: &armcompute.DiskProperties{ + EncryptionSettingsCollection: nil, + }, + }, + }, + }, + want: apitypes.RootVolumeEncryptedNo, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isEncrypted(tt.args.disk); got != tt.want { + t.Errorf("isEncrypted() = %v, want %v", got, tt.want) + } + }) + } +} From c034ac02d18763e48e84ff9c0d1560ff0337f813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Fri, 23 Feb 2024 10:35:28 +0100 Subject: [PATCH 7/9] fix: wrapcheck lint errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/scanner/blob.go | 1 + provider/v2/azure/scanner/networkInterface.go | 5 +++-- provider/v2/azure/scanner/scanner.go | 1 + provider/v2/azure/scanner/scannerVm.go | 5 +++-- provider/v2/azure/scanner/snapshot.go | 6 ++++-- provider/v2/azure/scanner/targetDisk.go | 5 +++-- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/provider/v2/azure/scanner/blob.go b/provider/v2/azure/scanner/blob.go index b65e9cd15..ff2465e52 100644 --- a/provider/v2/azure/scanner/blob.go +++ b/provider/v2/azure/scanner/blob.go @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// nolint: wrapcheck package scanner import ( diff --git a/provider/v2/azure/scanner/networkInterface.go b/provider/v2/azure/scanner/networkInterface.go index ee5bb97a6..21dc9be0e 100644 --- a/provider/v2/azure/scanner/networkInterface.go +++ b/provider/v2/azure/scanner/networkInterface.go @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// nolint: wrapcheck package scanner import ( @@ -88,11 +89,11 @@ func (s *Scanner) ensureNetworkInterfaceDeleted(ctx context.Context, config *pro "interface", func() error { _, err := s.InterfacesClient.Get(ctx, s.Config.ScannerResourceGroup, nicName, nil) - return err // nolint: wrapcheck + return err }, func() error { _, err := s.InterfacesClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, nicName, nil) - return err // nolint: wrapcheck + return err }, NetworkInterfaceDeleteEstimateTime, ) diff --git a/provider/v2/azure/scanner/scanner.go b/provider/v2/azure/scanner/scanner.go index c90aa7cf3..8a30231c6 100644 --- a/provider/v2/azure/scanner/scanner.go +++ b/provider/v2/azure/scanner/scanner.go @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// nolint: wrapcheck package scanner import ( diff --git a/provider/v2/azure/scanner/scannerVm.go b/provider/v2/azure/scanner/scannerVm.go index 9ff1937c8..480511fc1 100644 --- a/provider/v2/azure/scanner/scannerVm.go +++ b/provider/v2/azure/scanner/scannerVm.go @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// nolint:wrapcheck package scanner import ( @@ -137,11 +138,11 @@ func (s *Scanner) ensureScannerVirtualMachineDeleted(ctx context.Context, config "virtual machine", func() error { _, err := s.VMClient.Get(ctx, s.Config.ScannerResourceGroup, vmName, nil) - return err // nolint: wrapcheck + return err }, func() error { _, err := s.VMClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, vmName, nil) - return err // nolint: wrapcheck + return err }, VMDeleteEstimateTime, ) diff --git a/provider/v2/azure/scanner/snapshot.go b/provider/v2/azure/scanner/snapshot.go index a330bd5d0..9518b7638 100644 --- a/provider/v2/azure/scanner/snapshot.go +++ b/provider/v2/azure/scanner/snapshot.go @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// nolint:wrapcheck package scanner import ( @@ -73,15 +74,16 @@ func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *pro func (s *Scanner) ensureSnapshotDeleted(ctx context.Context, config *provider.ScanJobConfig) error { snapshotName := snapshotNameFromJobConfig(config) + // nolint:wrapcheck return common.EnsureDeleted( "snapshot", func() error { _, err := s.SnapshotsClient.Get(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) - return err // nolint: wrapcheck + return err }, func() error { _, err := s.SnapshotsClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) - return err // nolint: wrapcheck + return err }, SnapshotDeleteEstimateTime, ) diff --git a/provider/v2/azure/scanner/targetDisk.go b/provider/v2/azure/scanner/targetDisk.go index c49412c14..c5ebb5344 100644 --- a/provider/v2/azure/scanner/targetDisk.go +++ b/provider/v2/azure/scanner/targetDisk.go @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// nolint: wrapcheck package scanner import ( @@ -122,11 +123,11 @@ func (s *Scanner) ensureTargetDiskDeleted(ctx context.Context, config *provider. "target disk", func() error { _, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) - return err // nolint: wrapcheck + return err }, func() error { _, err := s.DisksClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, volumeName, nil) - return err // nolint: wrapcheck + return err }, DiskDeleteEstimateTime, ) From a8ae5bd52f19641a4483b2d162bb784fde4f8281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Mon, 26 Feb 2024 14:21:54 +0100 Subject: [PATCH 8/9] refactor: common.go to utils, config.go to scanner package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/provider.go | 11 +++++----- provider/v2/azure/scanner/blob.go | 20 +++++++++---------- .../v2/azure/{common => scanner}/config.go | 2 +- provider/v2/azure/scanner/networkInterface.go | 8 ++++---- provider/v2/azure/scanner/scanner.go | 6 +++--- provider/v2/azure/scanner/scannerVm.go | 12 +++++------ provider/v2/azure/scanner/snapshot.go | 8 ++++---- provider/v2/azure/scanner/targetDisk.go | 12 +++++------ .../{common/common.go => utils/utils.go} | 2 +- 9 files changed, 40 insertions(+), 41 deletions(-) rename provider/v2/azure/{common => scanner}/config.go (99%) rename provider/v2/azure/{common/common.go => utils/utils.go} (99%) diff --git a/provider/v2/azure/provider.go b/provider/v2/azure/provider.go index 944223135..a55f560c7 100644 --- a/provider/v2/azure/provider.go +++ b/provider/v2/azure/provider.go @@ -24,7 +24,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5" apitypes "github.com/openclarity/vmclarity/api/types" - "github.com/openclarity/vmclarity/provider/v2/azure/common" "github.com/openclarity/vmclarity/provider/v2/azure/discoverer" "github.com/openclarity/vmclarity/provider/v2/azure/estimator" "github.com/openclarity/vmclarity/provider/v2/azure/scanner" @@ -41,12 +40,12 @@ func (p *Provider) Kind() apitypes.CloudProvider { } func New(_ context.Context) (*Provider, error) { - config, err := common.NewConfig() + scannerConfig, err := scanner.NewConfig() if err != nil { return nil, fmt.Errorf("failed to load configuration: %w", err) } - err = config.Validate() + err = scannerConfig.Validate() if err != nil { return nil, fmt.Errorf("failed to validate configuration: %w", err) } @@ -56,12 +55,12 @@ func New(_ context.Context) (*Provider, error) { return nil, fmt.Errorf("failed create managed identity credential: %w", err) } - networkClientFactory, err := armnetwork.NewClientFactory(config.SubscriptionID, cred, nil) + networkClientFactory, err := armnetwork.NewClientFactory(scannerConfig.SubscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create network client factory: %w", err) } - computeClientFactory, err := armcompute.NewClientFactory(config.SubscriptionID, cred, nil) + computeClientFactory, err := armcompute.NewClientFactory(scannerConfig.SubscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create compute client factory: %w", err) } @@ -78,7 +77,7 @@ func New(_ context.Context) (*Provider, error) { DisksClient: computeClientFactory.NewDisksClient(), InterfacesClient: networkClientFactory.NewInterfacesClient(), - Config: config, + Config: scannerConfig, }, Estimator: &estimator.Estimator{}, }, nil diff --git a/provider/v2/azure/scanner/blob.go b/provider/v2/azure/scanner/blob.go index ff2465e52..04fbee523 100644 --- a/provider/v2/azure/scanner/blob.go +++ b/provider/v2/azure/scanner/blob.go @@ -27,7 +27,7 @@ import ( "github.com/openclarity/vmclarity/core/to" "github.com/openclarity/vmclarity/provider" - "github.com/openclarity/vmclarity/provider/v2/azure/common" + "github.com/openclarity/vmclarity/provider/v2/azure/utils" ) var ( @@ -63,19 +63,19 @@ func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.S revokepoller, err := s.SnapshotsClient.BeginRevokeAccess(ctx, s.Config.ScannerResourceGroup, *snapshot.Name, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "revoking SAS access for snapshot %s", *snapshot.Name) + _, err := utils.HandleAzureRequestError(err, "revoking SAS access for snapshot %s", *snapshot.Name) return blobURL, err } _, err = revokepoller.PollUntilDone(ctx, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "waiting for SAS access to be revoked for snapshot %s", *snapshot.Name) + _, err := utils.HandleAzureRequestError(err, "waiting for SAS access to be revoked for snapshot %s", *snapshot.Name) return blobURL, err } return blobURL, nil } - notFound, err := common.HandleAzureRequestError(err, "getting blob %s", blobName) + notFound, err := utils.HandleAzureRequestError(err, "getting blob %s", blobName) if !notFound { return blobURL, err } @@ -89,13 +89,13 @@ func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.S DurationInSeconds: to.Ptr[int32](int32(snapshotSASAccessSeconds)), }, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "granting SAS access to snapshot %s", *snapshot.Name) + _, err := utils.HandleAzureRequestError(err, "granting SAS access to snapshot %s", *snapshot.Name) return blobURL, err } res, err := poller.PollUntilDone(ctx, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "waiting for SAS access to snapshot %s be granted", *snapshot.Name) + _, err := utils.HandleAzureRequestError(err, "waiting for SAS access to snapshot %s be granted", *snapshot.Name) return blobURL, err } @@ -103,7 +103,7 @@ func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.S _, err = blobClient.StartCopyFromURL(ctx, accessURL, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "starting copy from URL operation for blob %s", blobName) + _, err := utils.HandleAzureRequestError(err, "starting copy from URL operation for blob %s", blobName) return blobURL, err } @@ -120,7 +120,7 @@ func (s *Scanner) ensureBlobDeleted(ctx context.Context, config *provider.ScanJo getMetadata, err := blobClient.GetProperties(ctx, nil) if err != nil { - notFound, err := common.HandleAzureRequestError(err, "getting blob %s", blobName) + notFound, err := utils.HandleAzureRequestError(err, "getting blob %s", blobName) if notFound { return nil } @@ -131,7 +131,7 @@ func (s *Scanner) ensureBlobDeleted(ctx context.Context, config *provider.ScanJo if copyStatus == blob.CopyStatusTypePending { _, err = blobClient.AbortCopyFromURL(ctx, *getMetadata.CopyID, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "aborting copy from url for blob %s", blobName) + _, err := utils.HandleAzureRequestError(err, "aborting copy from url for blob %s", blobName) return err } return provider.RetryableErrorf(estimatedBlobAbortTime, "blob copy aborting") @@ -139,7 +139,7 @@ func (s *Scanner) ensureBlobDeleted(ctx context.Context, config *provider.ScanJo _, err = blobClient.Delete(ctx, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "deleting blob %s", blobName) + _, err := utils.HandleAzureRequestError(err, "deleting blob %s", blobName) return err } diff --git a/provider/v2/azure/common/config.go b/provider/v2/azure/scanner/config.go similarity index 99% rename from provider/v2/azure/common/config.go rename to provider/v2/azure/scanner/config.go index 939be22e5..0a973d9ac 100644 --- a/provider/v2/azure/common/config.go +++ b/provider/v2/azure/scanner/config.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package common +package scanner import ( "encoding/base64" diff --git a/provider/v2/azure/scanner/networkInterface.go b/provider/v2/azure/scanner/networkInterface.go index 21dc9be0e..87b33ffaa 100644 --- a/provider/v2/azure/scanner/networkInterface.go +++ b/provider/v2/azure/scanner/networkInterface.go @@ -24,7 +24,7 @@ import ( "github.com/openclarity/vmclarity/core/to" "github.com/openclarity/vmclarity/provider" - "github.com/openclarity/vmclarity/provider/v2/azure/common" + "github.com/openclarity/vmclarity/provider/v2/azure/utils" ) var ( @@ -48,7 +48,7 @@ func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.S return nicResp.Interface, nil } - notFound, err := common.HandleAzureRequestError(err, "getting interface %s", nicName) + notFound, err := utils.HandleAzureRequestError(err, "getting interface %s", nicName) if !notFound { return armnetwork.Interface{}, err } @@ -75,7 +75,7 @@ func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.S _, err = s.InterfacesClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, nicName, parameters, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "creating interface %s", nicName) + _, err := utils.HandleAzureRequestError(err, "creating interface %s", nicName) return armnetwork.Interface{}, err } @@ -85,7 +85,7 @@ func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.S func (s *Scanner) ensureNetworkInterfaceDeleted(ctx context.Context, config *provider.ScanJobConfig) error { nicName := networkInterfaceNameFromJobConfig(config) - return common.EnsureDeleted( + return utils.EnsureDeleted( "interface", func() error { _, err := s.InterfacesClient.Get(ctx, s.Config.ScannerResourceGroup, nicName, nil) diff --git a/provider/v2/azure/scanner/scanner.go b/provider/v2/azure/scanner/scanner.go index 8a30231c6..b3dd36f33 100644 --- a/provider/v2/azure/scanner/scanner.go +++ b/provider/v2/azure/scanner/scanner.go @@ -26,7 +26,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5" "github.com/openclarity/vmclarity/provider" - "github.com/openclarity/vmclarity/provider/v2/azure/common" + "github.com/openclarity/vmclarity/provider/v2/azure/utils" ) const ( @@ -43,7 +43,7 @@ type Scanner struct { DisksClient *armcompute.DisksClient InterfacesClient *armnetwork.InterfacesClient - Config *common.Config + Config *Config } // nolint:cyclop @@ -60,7 +60,7 @@ func (s *Scanner) RunAssetScan(ctx context.Context, config *provider.ScanJobConf assetVM, err := s.VMClient.Get(ctx, resourceGroup, vmName, nil) if err != nil { - _, err = common.HandleAzureRequestError(err, "getting asset virtual machine %s", vmName) + _, err = utils.HandleAzureRequestError(err, "getting asset virtual machine %s", vmName) return err } diff --git a/provider/v2/azure/scanner/scannerVm.go b/provider/v2/azure/scanner/scannerVm.go index 480511fc1..96d355ed7 100644 --- a/provider/v2/azure/scanner/scannerVm.go +++ b/provider/v2/azure/scanner/scannerVm.go @@ -28,7 +28,7 @@ import ( "github.com/openclarity/vmclarity/core/to" "github.com/openclarity/vmclarity/provider" "github.com/openclarity/vmclarity/provider/cloudinit" - "github.com/openclarity/vmclarity/provider/v2/azure/common" + "github.com/openclarity/vmclarity/provider/v2/azure/utils" ) var ( @@ -52,7 +52,7 @@ func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provi return vmResp.VirtualMachine, nil } - notFound, err := common.HandleAzureRequestError(err, "getting scanner virtual machine: %s", vmName) + notFound, err := utils.HandleAzureRequestError(err, "getting scanner virtual machine: %s", vmName) if !notFound { return armcompute.VirtualMachine{}, err } @@ -124,7 +124,7 @@ func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provi _, err = s.VMClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, vmName, parameters, nil) if err != nil { - _, err = common.HandleAzureRequestError(err, "creating virtual machine") + _, err = utils.HandleAzureRequestError(err, "creating virtual machine") return armcompute.VirtualMachine{}, err } @@ -134,7 +134,7 @@ func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provi func (s *Scanner) ensureScannerVirtualMachineDeleted(ctx context.Context, config *provider.ScanJobConfig) error { vmName := scannerVMNameFromJobConfig(config) - return common.EnsureDeleted( + return utils.EnsureDeleted( "virtual machine", func() error { _, err := s.VMClient.Get(ctx, s.Config.ScannerResourceGroup, vmName, nil) @@ -171,14 +171,14 @@ func (s *Scanner) ensureDiskAttachedToScannerVM(ctx context.Context, vm armcompu _, err := s.VMClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, *vm.Name, vm, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "attaching disk %s to VM %s", *disk.Name, *vm.Name) + _, err := utils.HandleAzureRequestError(err, "attaching disk %s to VM %s", *disk.Name, *vm.Name) return err } } diskResp, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, *disk.Name, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "getting disk %s", *disk.Name) + _, err := utils.HandleAzureRequestError(err, "getting disk %s", *disk.Name) return err } diff --git a/provider/v2/azure/scanner/snapshot.go b/provider/v2/azure/scanner/snapshot.go index 9518b7638..237adf80e 100644 --- a/provider/v2/azure/scanner/snapshot.go +++ b/provider/v2/azure/scanner/snapshot.go @@ -24,7 +24,7 @@ import ( "github.com/openclarity/vmclarity/core/to" "github.com/openclarity/vmclarity/provider" - "github.com/openclarity/vmclarity/provider/v2/azure/common" + "github.com/openclarity/vmclarity/provider/v2/azure/utils" ) var ( @@ -49,7 +49,7 @@ func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *pro return snapshotRes.Snapshot, nil } - notFound, err := common.HandleAzureRequestError(err, "getting snapshot %s", snapshotName) + notFound, err := utils.HandleAzureRequestError(err, "getting snapshot %s", snapshotName) if !notFound { return armcompute.Snapshot{}, err } @@ -64,7 +64,7 @@ func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *pro }, }, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "creating snapshot %s", snapshotName) + _, err := utils.HandleAzureRequestError(err, "creating snapshot %s", snapshotName) return armcompute.Snapshot{}, err } @@ -75,7 +75,7 @@ func (s *Scanner) ensureSnapshotDeleted(ctx context.Context, config *provider.Sc snapshotName := snapshotNameFromJobConfig(config) // nolint:wrapcheck - return common.EnsureDeleted( + return utils.EnsureDeleted( "snapshot", func() error { _, err := s.SnapshotsClient.Get(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) diff --git a/provider/v2/azure/scanner/targetDisk.go b/provider/v2/azure/scanner/targetDisk.go index c5ebb5344..9d1c6c49a 100644 --- a/provider/v2/azure/scanner/targetDisk.go +++ b/provider/v2/azure/scanner/targetDisk.go @@ -25,7 +25,7 @@ import ( "github.com/openclarity/vmclarity/core/to" "github.com/openclarity/vmclarity/provider" - "github.com/openclarity/vmclarity/provider/v2/azure/common" + "github.com/openclarity/vmclarity/provider/v2/azure/utils" ) var ( @@ -49,7 +49,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshot(ctx context.Context, config *pro return volumeRes.Disk, nil } - notFound, err := common.HandleAzureRequestError(err, "getting volume %s", volumeName) + notFound, err := utils.HandleAzureRequestError(err, "getting volume %s", volumeName) if !notFound { return armcompute.Disk{}, err } @@ -67,7 +67,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshot(ctx context.Context, config *pro }, }, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "creating disk %s", volumeName) + _, err := utils.HandleAzureRequestError(err, "creating disk %s", volumeName) return armcompute.Disk{}, err } @@ -91,7 +91,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con return volumeRes.Disk, nil } - notFound, err := common.HandleAzureRequestError(err, "getting volume %s", volumeName) + notFound, err := utils.HandleAzureRequestError(err, "getting volume %s", volumeName) if !notFound { return armcompute.Disk{}, err } @@ -110,7 +110,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con }, }, nil) if err != nil { - _, err := common.HandleAzureRequestError(err, "creating disk %s", volumeName) + _, err := utils.HandleAzureRequestError(err, "creating disk %s", volumeName) return armcompute.Disk{}, err } return armcompute.Disk{}, provider.RetryableErrorf(DiskEstimateProvisionTime, "disk creating") @@ -119,7 +119,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con func (s *Scanner) ensureTargetDiskDeleted(ctx context.Context, config *provider.ScanJobConfig) error { volumeName := volumeNameFromJobConfig(config) - return common.EnsureDeleted( + return utils.EnsureDeleted( "target disk", func() error { _, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) diff --git a/provider/v2/azure/common/common.go b/provider/v2/azure/utils/utils.go similarity index 99% rename from provider/v2/azure/common/common.go rename to provider/v2/azure/utils/utils.go index d459910f1..86cec8b3b 100644 --- a/provider/v2/azure/common/common.go +++ b/provider/v2/azure/utils/utils.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package common +package utils import ( "errors" From 81a93dbda313589932ec777a585d6f91566332ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20J=C3=A1ky?= Date: Mon, 26 Feb 2024 15:11:37 +0100 Subject: [PATCH 9/9] refactor: replace Scanner struct Config field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: András Jáky --- provider/v2/azure/{scanner => }/config.go | 2 +- provider/v2/azure/provider.go | 22 +++++++++++---- provider/v2/azure/scanner/blob.go | 6 ++-- provider/v2/azure/scanner/networkInterface.go | 14 +++++----- provider/v2/azure/scanner/scanner.go | 16 +++++++++-- provider/v2/azure/scanner/scannerVm.go | 28 +++++++++---------- provider/v2/azure/scanner/snapshot.go | 8 +++--- provider/v2/azure/scanner/targetDisk.go | 18 ++++++------ 8 files changed, 69 insertions(+), 45 deletions(-) rename provider/v2/azure/{scanner => }/config.go (99%) diff --git a/provider/v2/azure/scanner/config.go b/provider/v2/azure/config.go similarity index 99% rename from provider/v2/azure/scanner/config.go rename to provider/v2/azure/config.go index 0a973d9ac..eb2927001 100644 --- a/provider/v2/azure/scanner/config.go +++ b/provider/v2/azure/config.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package scanner +package azure import ( "encoding/base64" diff --git a/provider/v2/azure/provider.go b/provider/v2/azure/provider.go index a55f560c7..0ab62b956 100644 --- a/provider/v2/azure/provider.go +++ b/provider/v2/azure/provider.go @@ -40,12 +40,12 @@ func (p *Provider) Kind() apitypes.CloudProvider { } func New(_ context.Context) (*Provider, error) { - scannerConfig, err := scanner.NewConfig() + config, err := NewConfig() if err != nil { return nil, fmt.Errorf("failed to load configuration: %w", err) } - err = scannerConfig.Validate() + err = config.Validate() if err != nil { return nil, fmt.Errorf("failed to validate configuration: %w", err) } @@ -55,12 +55,12 @@ func New(_ context.Context) (*Provider, error) { return nil, fmt.Errorf("failed create managed identity credential: %w", err) } - networkClientFactory, err := armnetwork.NewClientFactory(scannerConfig.SubscriptionID, cred, nil) + networkClientFactory, err := armnetwork.NewClientFactory(config.SubscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create network client factory: %w", err) } - computeClientFactory, err := armcompute.NewClientFactory(scannerConfig.SubscriptionID, cred, nil) + computeClientFactory, err := armcompute.NewClientFactory(config.SubscriptionID, cred, nil) if err != nil { return nil, fmt.Errorf("failed to create compute client factory: %w", err) } @@ -77,7 +77,19 @@ func New(_ context.Context) (*Provider, error) { DisksClient: computeClientFactory.NewDisksClient(), InterfacesClient: networkClientFactory.NewInterfacesClient(), - Config: scannerConfig, + SubscriptionID: config.SubscriptionID, + ScannerLocation: config.ScannerLocation, + ScannerResourceGroup: config.ScannerResourceGroup, + ScannerSubnet: config.ScannerSubnet, + ScannerPublicKey: string(config.ScannerPublicKey), + ScannerVMSize: config.ScannerVMSize, + ScannerImagePublisher: config.ScannerImagePublisher, + ScannerImageOffer: config.ScannerImageOffer, + ScannerImageSKU: config.ScannerImageSKU, + ScannerImageVersion: config.ScannerImageVersion, + ScannerSecurityGroup: config.ScannerSecurityGroup, + ScannerStorageAccountName: config.ScannerStorageAccountName, + ScannerStorageContainerName: config.ScannerStorageContainerName, }, Estimator: &estimator.Estimator{}, }, nil diff --git a/provider/v2/azure/scanner/blob.go b/provider/v2/azure/scanner/blob.go index 04fbee523..ff3bd92d6 100644 --- a/provider/v2/azure/scanner/blob.go +++ b/provider/v2/azure/scanner/blob.go @@ -42,7 +42,7 @@ func blobNameFromJobConfig(config *provider.ScanJobConfig) string { } func (s *Scanner) blobURLFromBlobName(blobName string) string { - return fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", s.Config.ScannerStorageAccountName, s.Config.ScannerStorageContainerName, blobName) + return fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", s.ScannerStorageAccountName, s.ScannerStorageContainerName, blobName) } func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.ScanJobConfig, snapshot armcompute.Snapshot) (string, error) { @@ -61,7 +61,7 @@ func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.S return blobURL, provider.RetryableErrorf(estimatedBlobCopyTime, "blob is still copying") } - revokepoller, err := s.SnapshotsClient.BeginRevokeAccess(ctx, s.Config.ScannerResourceGroup, *snapshot.Name, nil) + revokepoller, err := s.SnapshotsClient.BeginRevokeAccess(ctx, s.ScannerResourceGroup, *snapshot.Name, nil) if err != nil { _, err := utils.HandleAzureRequestError(err, "revoking SAS access for snapshot %s", *snapshot.Name) return blobURL, err @@ -84,7 +84,7 @@ func (s *Scanner) ensureBlobFromSnapshot(ctx context.Context, config *provider.S // atomically with starting the CopyFromUrl Operation because // GrantAccess only provides the URL once, and we don't want to store // it. - poller, err := s.SnapshotsClient.BeginGrantAccess(ctx, s.Config.ScannerResourceGroup, *snapshot.Name, armcompute.GrantAccessData{ + poller, err := s.SnapshotsClient.BeginGrantAccess(ctx, s.ScannerResourceGroup, *snapshot.Name, armcompute.GrantAccessData{ Access: to.Ptr(armcompute.AccessLevelRead), DurationInSeconds: to.Ptr[int32](int32(snapshotSASAccessSeconds)), }, nil) diff --git a/provider/v2/azure/scanner/networkInterface.go b/provider/v2/azure/scanner/networkInterface.go index 87b33ffaa..0179cb2f2 100644 --- a/provider/v2/azure/scanner/networkInterface.go +++ b/provider/v2/azure/scanner/networkInterface.go @@ -39,7 +39,7 @@ func networkInterfaceNameFromJobConfig(config *provider.ScanJobConfig) string { func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.ScanJobConfig) (armnetwork.Interface, error) { nicName := networkInterfaceNameFromJobConfig(config) - nicResp, err := s.InterfacesClient.Get(ctx, s.Config.ScannerResourceGroup, nicName, nil) + nicResp, err := s.InterfacesClient.Get(ctx, s.ScannerResourceGroup, nicName, nil) if err == nil { if *nicResp.Interface.Properties.ProvisioningState != provisioningStateSucceeded { return nicResp.Interface, provider.RetryableErrorf(NetworkInterfaceEstimateProvisionTime, "interface is not ready yet, provisioning state: %s", *nicResp.Interface.Properties.ProvisioningState) @@ -54,7 +54,7 @@ func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.S } parameters := armnetwork.Interface{ - Location: to.Ptr(s.Config.ScannerLocation), + Location: to.Ptr(s.ScannerLocation), Properties: &armnetwork.InterfacePropertiesFormat{ IPConfigurations: []*armnetwork.InterfaceIPConfiguration{ { @@ -62,18 +62,18 @@ func (s *Scanner) ensureNetworkInterface(ctx context.Context, config *provider.S Properties: &armnetwork.InterfaceIPConfigurationPropertiesFormat{ PrivateIPAllocationMethod: to.Ptr(armnetwork.IPAllocationMethodDynamic), Subnet: &armnetwork.Subnet{ - ID: to.Ptr(s.Config.ScannerSubnet), + ID: to.Ptr(s.ScannerSubnet), }, }, }, }, NetworkSecurityGroup: &armnetwork.SecurityGroup{ - ID: to.Ptr(s.Config.ScannerSecurityGroup), + ID: to.Ptr(s.ScannerSecurityGroup), }, }, } - _, err = s.InterfacesClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, nicName, parameters, nil) + _, err = s.InterfacesClient.BeginCreateOrUpdate(ctx, s.ScannerResourceGroup, nicName, parameters, nil) if err != nil { _, err := utils.HandleAzureRequestError(err, "creating interface %s", nicName) return armnetwork.Interface{}, err @@ -88,11 +88,11 @@ func (s *Scanner) ensureNetworkInterfaceDeleted(ctx context.Context, config *pro return utils.EnsureDeleted( "interface", func() error { - _, err := s.InterfacesClient.Get(ctx, s.Config.ScannerResourceGroup, nicName, nil) + _, err := s.InterfacesClient.Get(ctx, s.ScannerResourceGroup, nicName, nil) return err }, func() error { - _, err := s.InterfacesClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, nicName, nil) + _, err := s.InterfacesClient.BeginDelete(ctx, s.ScannerResourceGroup, nicName, nil) return err }, NetworkInterfaceDeleteEstimateTime, diff --git a/provider/v2/azure/scanner/scanner.go b/provider/v2/azure/scanner/scanner.go index b3dd36f33..d6623f421 100644 --- a/provider/v2/azure/scanner/scanner.go +++ b/provider/v2/azure/scanner/scanner.go @@ -43,7 +43,19 @@ type Scanner struct { DisksClient *armcompute.DisksClient InterfacesClient *armnetwork.InterfacesClient - Config *Config + SubscriptionID string + ScannerLocation string + ScannerResourceGroup string + ScannerSubnet string + ScannerPublicKey string + ScannerVMSize string + ScannerImagePublisher string + ScannerImageOffer string + ScannerImageSKU string + ScannerImageVersion string + ScannerSecurityGroup string + ScannerStorageAccountName string + ScannerStorageContainerName string } // nolint:cyclop @@ -70,7 +82,7 @@ func (s *Scanner) RunAssetScan(ctx context.Context, config *provider.ScanJobConf } var disk armcompute.Disk - if *assetVM.Location == s.Config.ScannerLocation { + if *assetVM.Location == s.ScannerLocation { disk, err = s.ensureManagedDiskFromSnapshot(ctx, config, snapshot) if err != nil { return fmt.Errorf("failed to ensure managed disk created from snapshot: %w", err) diff --git a/provider/v2/azure/scanner/scannerVm.go b/provider/v2/azure/scanner/scannerVm.go index 96d355ed7..ad15f423b 100644 --- a/provider/v2/azure/scanner/scannerVm.go +++ b/provider/v2/azure/scanner/scannerVm.go @@ -44,7 +44,7 @@ func scannerVMNameFromJobConfig(config *provider.ScanJobConfig) string { func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provider.ScanJobConfig, networkInterface armnetwork.Interface) (armcompute.VirtualMachine, error) { vmName := scannerVMNameFromJobConfig(config) - vmResp, err := s.VMClient.Get(ctx, s.Config.ScannerResourceGroup, vmName, nil) + vmResp, err := s.VMClient.Get(ctx, s.ScannerResourceGroup, vmName, nil) if err == nil { if *vmResp.VirtualMachine.Properties.ProvisioningState != provisioningStateSucceeded { return vmResp.VirtualMachine, provider.RetryableErrorf(VMCreateEstimateProvisionTime, "VM is not ready yet, provisioning state: %s", *vmResp.VirtualMachine.Properties.ProvisioningState) @@ -64,21 +64,21 @@ func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provi userDataBase64 := base64.StdEncoding.EncodeToString([]byte(userData)) parameters := armcompute.VirtualMachine{ - Location: to.Ptr(s.Config.ScannerLocation), + Location: to.Ptr(s.ScannerLocation), Identity: &armcompute.VirtualMachineIdentity{ // Scanners don't need access to Azure so no need for an Identity Type: to.Ptr(armcompute.ResourceIdentityTypeNone), }, Properties: &armcompute.VirtualMachineProperties{ HardwareProfile: &armcompute.HardwareProfile{ - VMSize: to.Ptr(armcompute.VirtualMachineSizeTypes(s.Config.ScannerVMSize)), + VMSize: to.Ptr(armcompute.VirtualMachineSizeTypes(s.ScannerVMSize)), }, StorageProfile: &armcompute.StorageProfile{ ImageReference: &armcompute.ImageReference{ - Publisher: to.Ptr(s.Config.ScannerImagePublisher), - SKU: to.Ptr(s.Config.ScannerImageSKU), - Version: to.Ptr(s.Config.ScannerImageVersion), - Offer: to.Ptr(s.Config.ScannerImageOffer), + Publisher: to.Ptr(s.ScannerImagePublisher), + SKU: to.Ptr(s.ScannerImageSKU), + Version: to.Ptr(s.ScannerImageVersion), + Offer: to.Ptr(s.ScannerImageOffer), }, OSDisk: &armcompute.OSDisk{ Name: to.Ptr(vmName + "-rootvolume"), @@ -111,18 +111,18 @@ func (s *Scanner) ensureScannerVirtualMachine(ctx context.Context, config *provi }, } - if s.Config.ScannerPublicKey != "" { + if s.ScannerPublicKey != "" { parameters.Properties.OSProfile.LinuxConfiguration.SSH = &armcompute.SSHConfiguration{ PublicKeys: []*armcompute.SSHPublicKey{ { Path: to.Ptr(fmt.Sprintf("/home/%s/.ssh/authorized_keys", "vmclarity")), - KeyData: to.Ptr(string(s.Config.ScannerPublicKey)), + KeyData: to.Ptr(s.ScannerPublicKey), }, }, } } - _, err = s.VMClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, vmName, parameters, nil) + _, err = s.VMClient.BeginCreateOrUpdate(ctx, s.ScannerResourceGroup, vmName, parameters, nil) if err != nil { _, err = utils.HandleAzureRequestError(err, "creating virtual machine") return armcompute.VirtualMachine{}, err @@ -137,11 +137,11 @@ func (s *Scanner) ensureScannerVirtualMachineDeleted(ctx context.Context, config return utils.EnsureDeleted( "virtual machine", func() error { - _, err := s.VMClient.Get(ctx, s.Config.ScannerResourceGroup, vmName, nil) + _, err := s.VMClient.Get(ctx, s.ScannerResourceGroup, vmName, nil) return err }, func() error { - _, err := s.VMClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, vmName, nil) + _, err := s.VMClient.BeginDelete(ctx, s.ScannerResourceGroup, vmName, nil) return err }, VMDeleteEstimateTime, @@ -169,14 +169,14 @@ func (s *Scanner) ensureDiskAttachedToScannerVM(ctx context.Context, vm armcompu }, } - _, err := s.VMClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, *vm.Name, vm, nil) + _, err := s.VMClient.BeginCreateOrUpdate(ctx, s.ScannerResourceGroup, *vm.Name, vm, nil) if err != nil { _, err := utils.HandleAzureRequestError(err, "attaching disk %s to VM %s", *disk.Name, *vm.Name) return err } } - diskResp, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, *disk.Name, nil) + diskResp, err := s.DisksClient.Get(ctx, s.ScannerResourceGroup, *disk.Name, nil) if err != nil { _, err := utils.HandleAzureRequestError(err, "getting disk %s", *disk.Name) return err diff --git a/provider/v2/azure/scanner/snapshot.go b/provider/v2/azure/scanner/snapshot.go index 237adf80e..470cacbf7 100644 --- a/provider/v2/azure/scanner/snapshot.go +++ b/provider/v2/azure/scanner/snapshot.go @@ -39,7 +39,7 @@ func snapshotNameFromJobConfig(config *provider.ScanJobConfig) string { func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *provider.ScanJobConfig, vm armcompute.VirtualMachine) (armcompute.Snapshot, error) { snapshotName := snapshotNameFromJobConfig(config) - snapshotRes, err := s.SnapshotsClient.Get(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) + snapshotRes, err := s.SnapshotsClient.Get(ctx, s.ScannerResourceGroup, snapshotName, nil) if err == nil { if *snapshotRes.Properties.ProvisioningState != provisioningStateSucceeded { return snapshotRes.Snapshot, provider.RetryableErrorf(SnapshotCreateEstimateProvisionTime, "snapshot is not ready yet") @@ -54,7 +54,7 @@ func (s *Scanner) ensureSnapshotForVMRootVolume(ctx context.Context, config *pro return armcompute.Snapshot{}, err } - _, err = s.SnapshotsClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, snapshotName, armcompute.Snapshot{ + _, err = s.SnapshotsClient.BeginCreateOrUpdate(ctx, s.ScannerResourceGroup, snapshotName, armcompute.Snapshot{ Location: vm.Location, Properties: &armcompute.SnapshotProperties{ CreationData: &armcompute.CreationData{ @@ -78,11 +78,11 @@ func (s *Scanner) ensureSnapshotDeleted(ctx context.Context, config *provider.Sc return utils.EnsureDeleted( "snapshot", func() error { - _, err := s.SnapshotsClient.Get(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) + _, err := s.SnapshotsClient.Get(ctx, s.ScannerResourceGroup, snapshotName, nil) return err }, func() error { - _, err := s.SnapshotsClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, snapshotName, nil) + _, err := s.SnapshotsClient.BeginDelete(ctx, s.ScannerResourceGroup, snapshotName, nil) return err }, SnapshotDeleteEstimateTime, diff --git a/provider/v2/azure/scanner/targetDisk.go b/provider/v2/azure/scanner/targetDisk.go index 9d1c6c49a..409b1399a 100644 --- a/provider/v2/azure/scanner/targetDisk.go +++ b/provider/v2/azure/scanner/targetDisk.go @@ -40,7 +40,7 @@ func volumeNameFromJobConfig(config *provider.ScanJobConfig) string { func (s *Scanner) ensureManagedDiskFromSnapshot(ctx context.Context, config *provider.ScanJobConfig, snapshot armcompute.Snapshot) (armcompute.Disk, error) { volumeName := volumeNameFromJobConfig(config) - volumeRes, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + volumeRes, err := s.DisksClient.Get(ctx, s.ScannerResourceGroup, volumeName, nil) if err == nil { if *volumeRes.Disk.Properties.ProvisioningState != provisioningStateSucceeded { return volumeRes.Disk, provider.RetryableErrorf(DiskEstimateProvisionTime, "volume is not ready yet, provisioning state: %s", *volumeRes.Disk.Properties.ProvisioningState) @@ -54,8 +54,8 @@ func (s *Scanner) ensureManagedDiskFromSnapshot(ctx context.Context, config *pro return armcompute.Disk{}, err } - _, err = s.DisksClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, volumeName, armcompute.Disk{ - Location: to.Ptr(s.Config.ScannerLocation), + _, err = s.DisksClient.BeginCreateOrUpdate(ctx, s.ScannerResourceGroup, volumeName, armcompute.Disk{ + Location: to.Ptr(s.ScannerLocation), SKU: &armcompute.DiskSKU{ Name: to.Ptr(armcompute.DiskStorageAccountTypesStandardSSDLRS), }, @@ -82,7 +82,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con volumeName := volumeNameFromJobConfig(config) - volumeRes, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + volumeRes, err := s.DisksClient.Get(ctx, s.ScannerResourceGroup, volumeName, nil) if err == nil { if *volumeRes.Disk.Properties.ProvisioningState != provisioningStateSucceeded { return volumeRes.Disk, provider.RetryableErrorf(DiskEstimateProvisionTime, "volume is not ready yet, provisioning state: %s", *volumeRes.Disk.Properties.ProvisioningState) @@ -96,8 +96,8 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con return armcompute.Disk{}, err } - _, err = s.DisksClient.BeginCreateOrUpdate(ctx, s.Config.ScannerResourceGroup, volumeName, armcompute.Disk{ - Location: to.Ptr(s.Config.ScannerLocation), + _, err = s.DisksClient.BeginCreateOrUpdate(ctx, s.ScannerResourceGroup, volumeName, armcompute.Disk{ + Location: to.Ptr(s.ScannerLocation), SKU: &armcompute.DiskSKU{ Name: to.Ptr(armcompute.DiskStorageAccountTypesStandardSSDLRS), }, @@ -105,7 +105,7 @@ func (s *Scanner) ensureManagedDiskFromSnapshotInDifferentRegion(ctx context.Con CreationData: &armcompute.CreationData{ CreateOption: to.Ptr(armcompute.DiskCreateOptionImport), SourceURI: to.Ptr(blobURL), - StorageAccountID: to.Ptr(fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", s.Config.SubscriptionID, s.Config.ScannerResourceGroup, s.Config.ScannerStorageAccountName)), + StorageAccountID: to.Ptr(fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", s.SubscriptionID, s.ScannerResourceGroup, s.ScannerStorageAccountName)), }, }, }, nil) @@ -122,11 +122,11 @@ func (s *Scanner) ensureTargetDiskDeleted(ctx context.Context, config *provider. return utils.EnsureDeleted( "target disk", func() error { - _, err := s.DisksClient.Get(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + _, err := s.DisksClient.Get(ctx, s.ScannerResourceGroup, volumeName, nil) return err }, func() error { - _, err := s.DisksClient.BeginDelete(ctx, s.Config.ScannerResourceGroup, volumeName, nil) + _, err := s.DisksClient.BeginDelete(ctx, s.ScannerResourceGroup, volumeName, nil) return err }, DiskDeleteEstimateTime,