Migrate Storage sdk to Track2 for allowing Managed Identity Cluster feature to disable shared access keys (#3878)

* ARO-9711 assign cluster storage blob contributor to fpsp/wimi
* ARO-9711 migrate armstorage sdk to track2
* ARO-9711-use-non-account-key-auth-for-blobs-miwi-only
* ARO-9711 update mock import to uber mocks
* ARO-9711 fix e2e error for blob access
* ARO-9711 resolve PR comments
* ARO-9711 update Blob Client naming and comments
* ARO-9711 resolved comments and removed repeated blobClient
* ARO-9711 add clientOptions to blobManager constructor
This commit is contained in:
Rajdeep Chauhan 2024-10-22 15:54:06 -04:00 коммит произвёл GitHub
Родитель 91b9fda3d1
Коммит 3b6426c8c1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
29 изменённых файлов: 663 добавлений и 369 удалений

Просмотреть файл

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/msi-dataplane/pkg/dataplane" "github.com/Azure/msi-dataplane/pkg/dataplane"
@ -32,7 +33,6 @@ import (
"github.com/Azure/ARO-RP/pkg/metrics" "github.com/Azure/ARO-RP/pkg/metrics"
aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned" aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned"
"github.com/Azure/ARO-RP/pkg/operator/deploy" "github.com/Azure/ARO-RP/pkg/operator/deploy"
"github.com/Azure/ARO-RP/pkg/util/azblob"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armauthorization" "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armauthorization"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armmsi" "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armmsi"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armnetwork" "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armnetwork"
@ -43,6 +43,7 @@ import (
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network" "github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/privatedns" "github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/privatedns"
"github.com/Azure/ARO-RP/pkg/util/billing" "github.com/Azure/ARO-RP/pkg/util/billing"
"github.com/Azure/ARO-RP/pkg/util/blob"
"github.com/Azure/ARO-RP/pkg/util/clienthelper" "github.com/Azure/ARO-RP/pkg/util/clienthelper"
"github.com/Azure/ARO-RP/pkg/util/dns" "github.com/Azure/ARO-RP/pkg/util/dns"
"github.com/Azure/ARO-RP/pkg/util/encryption" "github.com/Azure/ARO-RP/pkg/util/encryption"
@ -51,6 +52,7 @@ import (
"github.com/Azure/ARO-RP/pkg/util/refreshable" "github.com/Azure/ARO-RP/pkg/util/refreshable"
"github.com/Azure/ARO-RP/pkg/util/storage" "github.com/Azure/ARO-RP/pkg/util/storage"
"github.com/Azure/ARO-RP/pkg/util/subnet" "github.com/Azure/ARO-RP/pkg/util/subnet"
"github.com/Azure/ARO-RP/pkg/util/token"
) )
type Interface interface { type Interface interface {
@ -105,7 +107,7 @@ type manager struct {
storage storage.Manager storage storage.Manager
subnet subnet.Manager // TODO: use armSubnets instead. https://issues.redhat.com/browse/ARO-4665 subnet subnet.Manager // TODO: use armSubnets instead. https://issues.redhat.com/browse/ARO-4665
graph graph.Manager graph graph.Manager
rpBlob azblob.Manager rpBlob blob.Manager
ch clienthelper.Interface ch clienthelper.Interface
kubernetescli kubernetes.Interface kubernetescli kubernetes.Interface
@ -120,9 +122,10 @@ type manager struct {
arocli aroclient.Interface arocli aroclient.Interface
imageregistrycli imageregistryclient.Interface imageregistrycli imageregistryclient.Interface
installViaHive bool installViaHive bool
adoptViaHive bool adoptViaHive bool
hiveClusterManager hive.ClusterManager hiveClusterManager hive.ClusterManager
fpServicePrincipalID string
aroOperatorDeployer deploy.Operator aroOperatorDeployer deploy.Operator
@ -162,6 +165,15 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
return nil, err return nil, err
} }
t, err := fpCredClusterTenant.GetToken(ctx, policy.TokenRequestOptions{Scopes: []string{_env.Environment().ResourceManagerScope}})
if err != nil {
return nil, err
}
fpspID, err := token.GetObjectId(t.Token)
if err != nil {
return nil, err
}
fpCredRPTenant, err := _env.FPNewClientCertificateCredential(_env.TenantID()) fpCredRPTenant, err := _env.FPNewClientCertificateCredential(_env.TenantID())
if err != nil { if err != nil {
return nil, err return nil, err
@ -172,8 +184,6 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
return nil, err return nil, err
} }
storage := storage.NewManager(_env, r.SubscriptionID, fpAuthorizer)
installViaHive, err := _env.LiveConfig().InstallViaHive(ctx) installViaHive, err := _env.LiveConfig().InstallViaHive(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -221,7 +231,12 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
return nil, err return nil, err
} }
rpBlob, err := azblob.NewManager(_env.Environment(), _env.SubscriptionID(), msiCredential) storage, err := storage.NewManager(r.SubscriptionID, _env.Environment().StorageEndpointSuffix, fpCredClusterTenant, doc.OpenShiftCluster.UsesWorkloadIdentity(), clientOptions)
if err != nil {
return nil, err
}
rpBlob, err := blob.NewManager(_env.SubscriptionID(), msiCredential, clientOptions)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,6 +300,7 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
now: func() time.Time { return time.Now() }, now: func() time.Time { return time.Now() },
openShiftClusterDocumentVersioner: new(openShiftClusterDocumentVersionerService), openShiftClusterDocumentVersioner: new(openShiftClusterDocumentVersionerService),
platformWorkloadIdentityRolesByVersion: platformWorkloadIdentityRolesByVersion, platformWorkloadIdentityRolesByVersion: platformWorkloadIdentityRolesByVersion,
fpServicePrincipalID: fpspID,
} }
if doc.OpenShiftCluster.UsesWorkloadIdentity() { if doc.OpenShiftCluster.UsesWorkloadIdentity() {

Просмотреть файл

@ -13,7 +13,6 @@ import (
"time" "time"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network" mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network"
mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features" mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
"github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest"
@ -508,11 +507,11 @@ func (m *manager) Delete(ctx context.Context) error {
if m.doc.OpenShiftCluster.UsesWorkloadIdentity() { if m.doc.OpenShiftCluster.UsesWorkloadIdentity() {
m.log.Printf("deleting OIDC configuration") m.log.Printf("deleting OIDC configuration")
blobContainerURL := oidcbuilder.GenerateBlobContainerURL(m.env) blobContainerURL := oidcbuilder.GenerateBlobContainerURL(m.env)
azBlobClient, err := m.rpBlob.GetAZBlobClient(blobContainerURL, &azblob.ClientOptions{}) blobsClient, err := m.rpBlob.GetBlobsClient(blobContainerURL)
if err != nil { if err != nil {
return err return err
} }
err = oidcbuilder.DeleteOidcFolder(ctx, oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, m.doc.ID), azBlobClient) err = oidcbuilder.DeleteOidcFolder(ctx, oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, m.doc.ID), blobsClient)
if err != nil { if err != nil {
return err return err
} }

Просмотреть файл

@ -14,7 +14,6 @@ import (
"time" "time"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network" mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network"
mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features" mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
"github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest"
@ -25,6 +24,7 @@ import (
"github.com/Azure/ARO-RP/pkg/api" "github.com/Azure/ARO-RP/pkg/api"
apisubnet "github.com/Azure/ARO-RP/pkg/api/util/subnet" apisubnet "github.com/Azure/ARO-RP/pkg/api/util/subnet"
"github.com/Azure/ARO-RP/pkg/cluster/graph"
"github.com/Azure/ARO-RP/pkg/env" "github.com/Azure/ARO-RP/pkg/env"
"github.com/Azure/ARO-RP/pkg/util/arm" "github.com/Azure/ARO-RP/pkg/util/arm"
"github.com/Azure/ARO-RP/pkg/util/oidcbuilder" "github.com/Azure/ARO-RP/pkg/util/oidcbuilder"
@ -62,12 +62,12 @@ func (m *manager) createOIDC(ctx context.Context) error {
return err return err
} }
azBlobClient, err := m.rpBlob.GetAZBlobClient(oidcBuilder.GetBlobContainerURL(), &azblob.ClientOptions{}) blobsClient, err := m.rpBlob.GetBlobsClient(oidcBuilder.GetBlobContainerURL())
if err != nil { if err != nil {
return err return err
} }
err = oidcBuilder.EnsureOIDCDocs(ctx, azBlobClient) err = oidcBuilder.EnsureOIDCDocs(ctx, blobsClient)
if err != nil { if err != nil {
return err return err
} }
@ -191,8 +191,8 @@ func (m *manager) deployBaseResourceTemplate(ctx context.Context) error {
resources := []*arm.Resource{ resources := []*arm.Resource{
m.storageAccount(clusterStorageAccountName, azureRegion, ocpSubnets, true), m.storageAccount(clusterStorageAccountName, azureRegion, ocpSubnets, true),
m.storageAccountBlobContainer(clusterStorageAccountName, "ignition"), m.storageAccountBlobContainer(clusterStorageAccountName, graph.IgnitionContainer),
m.storageAccountBlobContainer(clusterStorageAccountName, "aro"), m.storageAccountBlobContainer(clusterStorageAccountName, graph.GraphContainer),
m.storageAccount(m.doc.OpenShiftCluster.Properties.ImageRegistryStorageAccountName, azureRegion, ocpSubnets, true), m.storageAccount(m.doc.OpenShiftCluster.Properties.ImageRegistryStorageAccountName, azureRegion, ocpSubnets, true),
m.storageAccountBlobContainer(m.doc.OpenShiftCluster.Properties.ImageRegistryStorageAccountName, "image-registry"), m.storageAccountBlobContainer(m.doc.OpenShiftCluster.Properties.ImageRegistryStorageAccountName, "image-registry"),
m.clusterNSG(infraID, azureRegion), m.clusterNSG(infraID, azureRegion),
@ -239,6 +239,14 @@ func (m *manager) deployBaseResourceTemplate(ctx context.Context) error {
t.Resources = append(t.Resources, m.denyAssignment()) t.Resources = append(t.Resources, m.denyAssignment())
} }
if m.doc.OpenShiftCluster.UsesWorkloadIdentity() {
storageBlobContributorRBAC, err := m.fpspStorageBlobContributorRBAC(clusterStorageAccountName, m.fpServicePrincipalID)
if err != nil {
return err
}
t.Resources = append(t.Resources, storageBlobContributorRBAC)
}
return arm.DeployTemplate(ctx, m.log, m.deployments, resourceGroup, "storage", t, nil) return arm.DeployTemplate(ctx, m.log, m.deployments, resourceGroup, "storage", t, nil)
} }

Просмотреть файл

@ -130,6 +130,20 @@ func (m *manager) workloadIdentityResourceGroupRBAC(roleID, objID string) *arm.R
return r return r
} }
func (m *manager) fpspStorageBlobContributorRBAC(storageAccountName, principalID string) (*arm.Resource, error) {
if !m.doc.OpenShiftCluster.UsesWorkloadIdentity() {
return nil, fmt.Errorf("fpspStorageBlobContributorRBAC called for a Cluster Service Principal cluster")
}
resourceTypeStorageAccount := "Microsoft.Storage/storageAccounts"
return rbac.ResourceRoleAssignmentWithName(
rbac.RoleStorageBlobDataContributor,
fmt.Sprintf("'%s'", principalID),
resourceTypeStorageAccount,
fmt.Sprintf("'%s'", storageAccountName),
fmt.Sprintf("concat('%s', '/Microsoft.Authorization/', guid(resourceId('%s', '%s')))", storageAccountName, resourceTypeStorageAccount, storageAccountName),
), nil
}
// storageAccount will return storage account resource. // storageAccount will return storage account resource.
// Legacy storage accounts (public) are not encrypted and cannot be retrofitted. // Legacy storage accounts (public) are not encrypted and cannot be retrofitted.
// The flag controls this behavior in update/create. // The flag controls this behavior in update/create.

Просмотреть файл

@ -4,14 +4,21 @@ package cluster
// Licensed under the Apache License 2.0. // Licensed under the Apache License 2.0.
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization" mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
"github.com/Azure/go-autorest/autorest/to" "github.com/Azure/go-autorest/autorest/to"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"go.uber.org/mock/gomock"
"github.com/Azure/ARO-RP/pkg/api" "github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/util/arm"
"github.com/Azure/ARO-RP/pkg/util/azureclient"
mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env"
"github.com/Azure/ARO-RP/pkg/util/rbac"
utilerror "github.com/Azure/ARO-RP/test/util/error"
) )
func TestDenyAssignment(t *testing.T) { func TestDenyAssignment(t *testing.T) {
@ -88,3 +95,79 @@ func TestDenyAssignment(t *testing.T) {
}) })
} }
} }
func TestFpspStorageBlobContributorRBAC(t *testing.T) {
storageAccountName := "clustertest"
fakePrincipalID := "fakeID"
resourceType := "Microsoft.Storage/storageAccounts"
resourceID := fmt.Sprintf("resourceId('%s', '%s')", resourceType, storageAccountName)
tests := []struct {
Name string
ClusterDocument *api.OpenShiftClusterDocument
ExpectedArmResource *arm.Resource
wantErr string
}{
{
Name: "Fail : cluster with ServicePrincipalProfile",
ClusterDocument: &api.OpenShiftClusterDocument{
OpenShiftCluster: &api.OpenShiftCluster{
Properties: api.OpenShiftClusterProperties{
ClusterProfile: api.ClusterProfile{
ResourceGroupID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-cluster",
},
ServicePrincipalProfile: &api.ServicePrincipalProfile{
SPObjectID: fakeClusterSPObjectId,
},
},
},
},
wantErr: "fpspStorageBlobContributorRBAC called for a Cluster Service Principal cluster",
},
{
Name: "Success : cluster with PlatformWorkloadIdentityProfile",
ClusterDocument: &api.OpenShiftClusterDocument{
OpenShiftCluster: &api.OpenShiftCluster{
Properties: api.OpenShiftClusterProperties{
PlatformWorkloadIdentityProfile: &api.PlatformWorkloadIdentityProfile{},
},
},
},
ExpectedArmResource: &arm.Resource{
Resource: mgmtauthorization.RoleAssignment{
Name: to.StringPtr("[concat('clustertest', '/Microsoft.Authorization/', guid(" + resourceID + "))]"),
Type: to.StringPtr(resourceType + "/providers/roleAssignments"),
RoleAssignmentPropertiesWithScope: &mgmtauthorization.RoleAssignmentPropertiesWithScope{
Scope: to.StringPtr("[" + resourceID + "]"),
RoleDefinitionID: to.StringPtr("[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '" + rbac.RoleStorageBlobDataContributor + "')]"),
PrincipalID: to.StringPtr("['" + fakePrincipalID + "']"),
PrincipalType: mgmtauthorization.ServicePrincipal,
},
},
APIVersion: azureclient.APIVersion("Microsoft.Authorization"),
DependsOn: []string{
"[" + resourceID + "]",
},
},
},
}
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
env := mock_env.NewMockInterface(controller)
m := &manager{
doc: tt.ClusterDocument,
env: env,
}
resource, err := m.fpspStorageBlobContributorRBAC(storageAccountName, fakePrincipalID)
utilerror.AssertErrorMessage(t, err, tt.wantErr)
if !reflect.DeepEqual(tt.ExpectedArmResource, resource) {
t.Error("resultant ARM resource isn't the same as expected.")
}
})
}
}

Просмотреть файл

@ -31,8 +31,9 @@ import (
"github.com/Azure/ARO-RP/pkg/env" "github.com/Azure/ARO-RP/pkg/env"
"github.com/Azure/ARO-RP/pkg/util/arm" "github.com/Azure/ARO-RP/pkg/util/arm"
"github.com/Azure/ARO-RP/pkg/util/azureclient" "github.com/Azure/ARO-RP/pkg/util/azureclient"
mock_azblob "github.com/Azure/ARO-RP/pkg/util/mocks/azblob" mock_azblob "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/azuresdk/azblob"
mock_features "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/features" mock_features "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/features"
mock_blob "github.com/Azure/ARO-RP/pkg/util/mocks/blob"
mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env" mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env"
mock_subnet "github.com/Azure/ARO-RP/pkg/util/mocks/subnet" mock_subnet "github.com/Azure/ARO-RP/pkg/util/mocks/subnet"
"github.com/Azure/ARO-RP/pkg/util/oidcbuilder" "github.com/Azure/ARO-RP/pkg/util/oidcbuilder"
@ -1436,11 +1437,12 @@ func TestCreateOIDC(t *testing.T) {
}, },
} }
testOIDCKeyBitSize := 256 testOIDCKeyBitSize := 256
uploadResponse := azblob.UploadBufferResponse{}
for _, tt := range []struct { for _, tt := range []struct {
name string name string
oc *api.OpenShiftClusterDocument oc *api.OpenShiftClusterDocument
mocks func(*mock_azblob.MockManager, *mock_env.MockInterface, *mock_azblob.MockAZBlobClient) mocks func(*mock_blob.MockManager, *mock_env.MockInterface, *mock_azblob.MockBlobsClient)
wantedOIDCIssuer *api.OIDCIssuer wantedOIDCIssuer *api.OIDCIssuer
wantErr string wantErr string
wantBoundServiceAccountSigningKey bool wantBoundServiceAccountSigningKey bool
@ -1494,15 +1496,15 @@ func TestCreateOIDC(t *testing.T) {
}, },
}, },
}, },
mocks: func(blob *mock_azblob.MockManager, menv *mock_env.MockInterface, azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blob *mock_blob.MockManager, menv *mock_env.MockInterface, blobsClient *mock_azblob.MockBlobsClient) {
menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(false) menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(false)
menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize) menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize)
menv.EXPECT().OIDCEndpoint().Return(afdEndpoint) menv.EXPECT().OIDCEndpoint().Return(afdEndpoint)
menv.EXPECT().OIDCStorageAccountName().Return(oidcStorageAccountName) menv.EXPECT().OIDCStorageAccountName().Return(oidcStorageAccountName)
menv.EXPECT().Environment().Return(&azureclient.PublicCloud) menv.EXPECT().Environment().Return(&azureclient.PublicCloud)
blob.EXPECT().GetAZBlobClient(blobContainerURL, &azblob.ClientOptions{}).Return(azblobClient, nil) blob.EXPECT().GetBlobsClient(blobContainerURL).Return(blobsClient, nil)
azblobClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.DiscoveryDocumentKey), gomock.Any()).Return(nil) blobsClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.DiscoveryDocumentKey), gomock.Any(), nil).Return(uploadResponse, nil)
azblobClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.JWKSKey), gomock.Any()).Return(nil) blobsClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.JWKSKey), gomock.Any(), nil).Return(uploadResponse, nil)
}, },
wantedOIDCIssuer: pointerutils.ToPtr(api.OIDCIssuer(prodOIDCIssuer)), wantedOIDCIssuer: pointerutils.ToPtr(api.OIDCIssuer(prodOIDCIssuer)),
wantBoundServiceAccountSigningKey: true, wantBoundServiceAccountSigningKey: true,
@ -1521,16 +1523,16 @@ func TestCreateOIDC(t *testing.T) {
}, },
}, },
}, },
mocks: func(blob *mock_azblob.MockManager, menv *mock_env.MockInterface, azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blob *mock_blob.MockManager, menv *mock_env.MockInterface, blobsClient *mock_azblob.MockBlobsClient) {
menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(true) menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(true)
menv.EXPECT().ResourceGroup().Return(resourceGroupName) menv.EXPECT().ResourceGroup().Return(resourceGroupName)
menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize) menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize)
menv.EXPECT().OIDCStorageAccountName().AnyTimes().Return(oidcStorageAccountName) menv.EXPECT().OIDCStorageAccountName().AnyTimes().Return(oidcStorageAccountName)
blob.EXPECT().GetContainerProperties(gomock.Any(), resourceGroupName, oidcStorageAccountName, oidcbuilder.WebContainer).Return(containerProperties, nil) blob.EXPECT().GetContainerProperties(gomock.Any(), resourceGroupName, oidcStorageAccountName, oidcbuilder.WebContainer).Return(containerProperties, nil)
menv.EXPECT().Environment().Return(&azureclient.PublicCloud) menv.EXPECT().Environment().Return(&azureclient.PublicCloud)
blob.EXPECT().GetAZBlobClient(blobContainerURL, &azblob.ClientOptions{}).Return(azblobClient, nil) blob.EXPECT().GetBlobsClient(blobContainerURL).Return(blobsClient, nil)
azblobClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.DiscoveryDocumentKey), gomock.Any()).Return(nil) blobsClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.DiscoveryDocumentKey), gomock.Any(), nil).Return(uploadResponse, nil)
azblobClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.JWKSKey), gomock.Any()).Return(nil) blobsClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.JWKSKey), gomock.Any(), nil).Return(uploadResponse, nil)
}, },
wantedOIDCIssuer: pointerutils.ToPtr(api.OIDCIssuer(devOIDCIssuer)), wantedOIDCIssuer: pointerutils.ToPtr(api.OIDCIssuer(devOIDCIssuer)),
wantBoundServiceAccountSigningKey: true, wantBoundServiceAccountSigningKey: true,
@ -1549,7 +1551,7 @@ func TestCreateOIDC(t *testing.T) {
}, },
}, },
}, },
mocks: func(blob *mock_azblob.MockManager, menv *mock_env.MockInterface, azblob *mock_azblob.MockAZBlobClient) { mocks: func(blob *mock_blob.MockManager, menv *mock_env.MockInterface, azblob *mock_azblob.MockBlobsClient) {
menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(true) menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(true)
menv.EXPECT().ResourceGroup().Return(resourceGroupName) menv.EXPECT().ResourceGroup().Return(resourceGroupName)
menv.EXPECT().OIDCStorageAccountName().AnyTimes().Return(oidcStorageAccountName) menv.EXPECT().OIDCStorageAccountName().AnyTimes().Return(oidcStorageAccountName)
@ -1559,7 +1561,7 @@ func TestCreateOIDC(t *testing.T) {
wantErr: "generic error", wantErr: "generic error",
}, },
{ {
name: "Fail - azBlobClient creation failure", name: "Fail - blobsClient creation failure",
oc: &api.OpenShiftClusterDocument{ oc: &api.OpenShiftClusterDocument{
Key: strings.ToLower(resourceID), Key: strings.ToLower(resourceID),
ID: clusterID, ID: clusterID,
@ -1572,13 +1574,13 @@ func TestCreateOIDC(t *testing.T) {
}, },
}, },
}, },
mocks: func(blob *mock_azblob.MockManager, menv *mock_env.MockInterface, azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blob *mock_blob.MockManager, menv *mock_env.MockInterface, blobsClient *mock_azblob.MockBlobsClient) {
menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(false) menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(false)
menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize) menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize)
menv.EXPECT().OIDCEndpoint().Return(afdEndpoint) menv.EXPECT().OIDCEndpoint().Return(afdEndpoint)
menv.EXPECT().OIDCStorageAccountName().Return(oidcStorageAccountName) menv.EXPECT().OIDCStorageAccountName().Return(oidcStorageAccountName)
menv.EXPECT().Environment().Return(&azureclient.PublicCloud) menv.EXPECT().Environment().Return(&azureclient.PublicCloud)
blob.EXPECT().GetAZBlobClient(blobContainerURL, &azblob.ClientOptions{}).Return(azblobClient, errors.New("generic error")) blob.EXPECT().GetBlobsClient(blobContainerURL).Return(blobsClient, errors.New("generic error"))
}, },
wantBoundServiceAccountSigningKey: false, wantBoundServiceAccountSigningKey: false,
wantErr: "generic error", wantErr: "generic error",
@ -1597,14 +1599,14 @@ func TestCreateOIDC(t *testing.T) {
}, },
}, },
}, },
mocks: func(blob *mock_azblob.MockManager, menv *mock_env.MockInterface, azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blob *mock_blob.MockManager, menv *mock_env.MockInterface, blobsClient *mock_azblob.MockBlobsClient) {
menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(false) menv.EXPECT().FeatureIsSet(env.FeatureRequireOIDCStorageWebEndpoint).Return(false)
menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize) menv.EXPECT().OIDCKeyBitSize().Return(testOIDCKeyBitSize)
menv.EXPECT().OIDCEndpoint().Return(afdEndpoint) menv.EXPECT().OIDCEndpoint().Return(afdEndpoint)
menv.EXPECT().OIDCStorageAccountName().Return(oidcStorageAccountName) menv.EXPECT().OIDCStorageAccountName().Return(oidcStorageAccountName)
menv.EXPECT().Environment().Return(&azureclient.PublicCloud) menv.EXPECT().Environment().Return(&azureclient.PublicCloud)
blob.EXPECT().GetAZBlobClient(blobContainerURL, &azblob.ClientOptions{}).Return(azblobClient, nil) blob.EXPECT().GetBlobsClient(blobContainerURL).Return(blobsClient, nil)
azblobClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.DiscoveryDocumentKey), gomock.Any()).Return(errors.New("generic error")) blobsClient.EXPECT().UploadBuffer(gomock.Any(), "", oidcbuilder.DocumentKey(oidcbuilder.GetBlobName(m.subscriptionDoc.Subscription.Properties.TenantID, clusterID), oidcbuilder.DiscoveryDocumentKey), gomock.Any(), nil).Return(uploadResponse, errors.New("generic error"))
}, },
wantBoundServiceAccountSigningKey: false, wantBoundServiceAccountSigningKey: false,
wantErr: "generic error", wantErr: "generic error",
@ -1616,11 +1618,11 @@ func TestCreateOIDC(t *testing.T) {
dbOpenShiftClusters, _ := testdatabase.NewFakeOpenShiftClusters() dbOpenShiftClusters, _ := testdatabase.NewFakeOpenShiftClusters()
rpBlobManager := mock_azblob.NewMockManager(controller) rpBlobManager := mock_blob.NewMockManager(controller)
env := mock_env.NewMockInterface(controller) env := mock_env.NewMockInterface(controller)
azBlobClient := mock_azblob.NewMockAZBlobClient(controller) blobsClient := mock_azblob.NewMockBlobsClient(controller)
if tt.mocks != nil { if tt.mocks != nil {
tt.mocks(rpBlobManager, env, azBlobClient) tt.mocks(rpBlobManager, env, blobsClient)
} }
f := testdatabase.NewFixture().WithOpenShiftClusters(dbOpenShiftClusters) f := testdatabase.NewFixture().WithOpenShiftClusters(dbOpenShiftClusters)

Просмотреть файл

@ -9,7 +9,7 @@ import (
"io" "io"
"strings" "strings"
mgmtstorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/Azure/ARO-RP/pkg/env" "github.com/Azure/ARO-RP/pkg/env"
@ -17,6 +17,12 @@ import (
"github.com/Azure/ARO-RP/pkg/util/storage" "github.com/Azure/ARO-RP/pkg/util/storage"
) )
const (
GraphContainer = "aro"
GraphBlob = "graph"
IgnitionContainer = "ignition"
)
type Manager interface { type Manager interface {
Exists(ctx context.Context, resourceGroup, account string) (bool, error) Exists(ctx context.Context, resourceGroup, account string) (bool, error)
LoadPersisted(ctx context.Context, resourceGroup, account string) (PersistedGraph, error) LoadPersisted(ctx context.Context, resourceGroup, account string) (PersistedGraph, error)
@ -43,13 +49,12 @@ func NewManager(env env.Interface, log *logrus.Entry, aead encryption.AEAD, stor
func (m *manager) Exists(ctx context.Context, resourceGroup, account string) (bool, error) { func (m *manager) Exists(ctx context.Context, resourceGroup, account string) (bool, error) {
m.log.Print("checking if graph exists") m.log.Print("checking if graph exists")
blobService, err := m.storage.BlobService(ctx, resourceGroup, account, mgmtstorage.Permissions("r"), mgmtstorage.SignedResourceTypesO) blobService, err := m.storage.BlobService(ctx, resourceGroup, account, armstorage.Permissions("r"), armstorage.SignedResourceTypesO)
if err != nil { if err != nil {
return false, err return false, err
} }
aro := blobService.GetContainerReference("aro") return blobService.BlobExists(ctx, GraphContainer, GraphBlob)
return aro.GetBlobReference("graph").Exists()
} }
func (m *manager) LoadPersisted(ctx context.Context, resourceGroup, account string) (PersistedGraph, error) { func (m *manager) LoadPersisted(ctx context.Context, resourceGroup, account string) (PersistedGraph, error) {
@ -73,20 +78,18 @@ func (m *manager) reloadAead(ctx context.Context) (err error) {
func (m *manager) loadPersisted(ctx context.Context, resourceGroup, account string) (PersistedGraph, error) { func (m *manager) loadPersisted(ctx context.Context, resourceGroup, account string) (PersistedGraph, error) {
m.log.Print("load persisted graph") m.log.Print("load persisted graph")
blobService, err := m.storage.BlobService(ctx, resourceGroup, account, mgmtstorage.Permissions("r"), mgmtstorage.SignedResourceTypesO) blobService, err := m.storage.BlobService(ctx, resourceGroup, account, armstorage.Permissions("r"), armstorage.SignedResourceTypesO)
if err != nil { if err != nil {
return nil, err return nil, err
} }
aro := blobService.GetContainerReference("aro") rc, err := blobService.DownloadStream(ctx, GraphContainer, GraphBlob, nil)
cluster := aro.GetBlobReference("graph")
rc, err := cluster.Get(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rc.Close() defer rc.Body.Close()
b, err := io.ReadAll(rc) b, err := io.ReadAll(rc.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

Просмотреть файл

@ -6,9 +6,9 @@ package cluster
import ( import (
"context" "context"
mgmtstorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
azstorage "github.com/Azure/azure-sdk-for-go/storage"
"github.com/Azure/ARO-RP/pkg/cluster/graph"
"github.com/Azure/ARO-RP/pkg/util/stringutils" "github.com/Azure/ARO-RP/pkg/util/stringutils"
) )
@ -38,12 +38,10 @@ func (m *manager) removeBootstrapIgnition(ctx context.Context) error {
resourceGroup := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/') resourceGroup := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
account := "cluster" + m.doc.OpenShiftCluster.Properties.StorageSuffix account := "cluster" + m.doc.OpenShiftCluster.Properties.StorageSuffix
blobService, err := m.storage.BlobService(ctx, resourceGroup, account, mgmtstorage.Permissions("d"), mgmtstorage.SignedResourceTypesC) blobService, err := m.storage.BlobService(ctx, resourceGroup, account, armstorage.Permissions("d"), armstorage.SignedResourceTypesC)
if err != nil { if err != nil {
return err return err
} }
bootstrapIgn := blobService.GetContainerReference("ignition") return blobService.DeleteContainer(ctx, graph.IgnitionContainer)
_, err = bootstrapIgn.DeleteIfExists(&azstorage.DeleteContainerOptions{})
return err
} }

Просмотреть файл

@ -35,7 +35,7 @@ const (
func (m *manager) generateWorkloadIdentityResources() (map[string]kruntime.Object, error) { func (m *manager) generateWorkloadIdentityResources() (map[string]kruntime.Object, error) {
if !m.doc.OpenShiftCluster.UsesWorkloadIdentity() { if !m.doc.OpenShiftCluster.UsesWorkloadIdentity() {
return nil, fmt.Errorf("generateWorkloadIdentityResources called for a CSP cluster") return nil, fmt.Errorf("generateWorkloadIdentityResources called for a Cluster Service Principal cluster")
} }
resources := map[string]kruntime.Object{} resources := map[string]kruntime.Object{}

Просмотреть файл

@ -36,7 +36,7 @@ func TestGenerateWorkloadIdentityResources(t *testing.T) {
}{ }{
{ {
name: "returns error if cluster is not using workload identity", name: "returns error if cluster is not using workload identity",
wantErr: "generateWorkloadIdentityResources called for a CSP cluster", wantErr: "generateWorkloadIdentityResources called for a Cluster Service Principal cluster",
}, },
{ {
name: "generates all expected resources", name: "generates all expected resources",

Просмотреть файл

@ -1,71 +0,0 @@
package azblob
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
azstorage "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/ARO-RP/pkg/util/azureclient"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armstorage"
)
type Manager interface {
GetContainerProperties(ctx context.Context, resourceGroupName string, accountName string, containerName string) (azstorage.AccountsClientGetPropertiesResponse, error)
GetAZBlobClient(blobContainerURL string, options *azblob.ClientOptions) (AZBlobClient, error)
}
type manager struct {
cred azcore.TokenCredential
account armstorage.AccountsClient
}
func NewManager(environment *azureclient.AROEnvironment, subscriptionID string, credential azcore.TokenCredential) (Manager, error) {
accountsClient, err := armstorage.NewAccountsClient(environment, subscriptionID, credential)
if err != nil {
return nil, err
}
return &manager{
cred: credential,
account: accountsClient,
}, nil
}
func (m *manager) GetContainerProperties(ctx context.Context, resourceGroupName string, accountName string, containerName string) (azstorage.AccountsClientGetPropertiesResponse, error) {
return m.account.GetProperties(ctx, resourceGroupName, accountName, &azstorage.AccountsClientGetPropertiesOptions{})
}
func (m *manager) GetAZBlobClient(blobContainerURL string, options *azblob.ClientOptions) (AZBlobClient, error) {
return NewAZBlobClient(blobContainerURL, m.cred, options)
}
type AZBlobClient interface {
UploadBuffer(ctx context.Context, containerName string, blobName string, buffer []byte) error
DeleteBlob(ctx context.Context, containerName string, blobName string) error
}
type azBlobClient struct {
client *azblob.Client
}
func NewAZBlobClient(blobContainerURL string, credential azcore.TokenCredential, options *azblob.ClientOptions) (AZBlobClient, error) {
client, err := azblob.NewClient(blobContainerURL, credential, options)
if err != nil {
return nil, err
}
return &azBlobClient{client: client}, nil
}
func (azBlobClient *azBlobClient) UploadBuffer(ctx context.Context, containerName string, blobName string, buffer []byte) error {
_, err := azBlobClient.client.UploadBuffer(ctx, containerName, blobName, buffer, &azblob.UploadBufferOptions{})
return err
}
func (azBlobClient *azBlobClient) DeleteBlob(ctx context.Context, containerName string, blobName string) error {
_, err := azBlobClient.client.DeleteBlob(ctx, containerName, blobName, &azblob.DeleteBlobOptions{})
return err
}

Просмотреть файл

@ -5,18 +5,16 @@ package armstorage
import ( import (
"context" "context"
"net/http"
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/ARO-RP/pkg/util/azureclient"
) )
// AccountsClient is a minimal interface for Azure AccountsClient // AccountsClient is a minimal interface for Azure AccountsClient
type AccountsClient interface { type AccountsClient interface {
GetProperties(ctx context.Context, resourceGroupName string, accountName string, options *armstorage.AccountsClientGetPropertiesOptions) (armstorage.AccountsClientGetPropertiesResponse, error) GetProperties(ctx context.Context, resourceGroupName string, accountName string, options *armstorage.AccountsClientGetPropertiesOptions) (armstorage.AccountsClientGetPropertiesResponse, error)
ListAccountSAS(ctx context.Context, resourceGroupName string, accountName string, parameters armstorage.AccountSasParameters, options *armstorage.AccountsClientListAccountSASOptions) (armstorage.AccountsClientListAccountSASResponse, error)
} }
type accountsClient struct { type accountsClient struct {
@ -26,18 +24,8 @@ type accountsClient struct {
var _ AccountsClient = &accountsClient{} var _ AccountsClient = &accountsClient{}
// NewAccountsClient creates a new AccountsClient // NewAccountsClient creates a new AccountsClient
func NewAccountsClient(environment *azureclient.AROEnvironment, subscriptionID string, credential azcore.TokenCredential) (AccountsClient, error) { func NewAccountsClient(subscriptionID string, credential azcore.TokenCredential, options *arm.ClientOptions) (AccountsClient, error) {
customRoundTripper := azureclient.NewCustomRoundTripper(http.DefaultTransport) clientFactory, err := armstorage.NewClientFactory(subscriptionID, credential, options)
options := arm.ClientOptions{
ClientOptions: azcore.ClientOptions{
Cloud: environment.Cloud,
Transport: &http.Client{
Transport: customRoundTripper,
},
},
}
clientFactory, err := armstorage.NewClientFactory(subscriptionID, credential, &options)
if err != nil { if err != nil {
return nil, err return nil, err
} }

Просмотреть файл

@ -0,0 +1,56 @@
package azblob
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
)
// BlobsClient is a minimal interface for Azure BlobsClient
type BlobsClient interface {
DownloadStream(ctx context.Context, containerName string, blobName string, o *azblob.DownloadStreamOptions) (azblob.DownloadStreamResponse, error)
UploadBuffer(ctx context.Context, containerName string, blobName string, buffer []byte, o *azblob.UploadBufferOptions) (azblob.UploadBufferResponse, error)
DeleteBlob(ctx context.Context, containerName string, blobName string, o *azblob.DeleteBlobOptions) (azblob.DeleteBlobResponse, error)
BlobsClientAddons
}
type blobsClient struct {
*azblob.Client
}
var _ BlobsClient = &blobsClient{}
// NewBlobsClientUsingSAS creates a new BlobsClient using SAS
func NewBlobsClientUsingSAS(sasURL string, options *arm.ClientOptions) (*blobsClient, error) {
azBlobOptions := &azblob.ClientOptions{
ClientOptions: (*options).ClientOptions,
}
client, err := azblob.NewClientWithNoCredential(sasURL, azBlobOptions)
if err != nil {
return nil, err
}
return &blobsClient{
Client: client,
}, nil
}
// NewBlobsClientUsingEntra creates a new BlobsClient Microsoft Entra credentials
func NewBlobsClientUsingEntra(serviceURL string, credential azcore.TokenCredential, options *arm.ClientOptions) (*blobsClient, error) {
azBlobOptions := &azblob.ClientOptions{
ClientOptions: (*options).ClientOptions,
}
client, err := azblob.NewClient(serviceURL, credential, azBlobOptions)
if err != nil {
return nil, err
}
return &blobsClient{
Client: client,
}, nil
}

Просмотреть файл

@ -0,0 +1,49 @@
package azblob
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
)
type BlobsClientAddons interface {
BlobExists(ctx context.Context, container string, blobPath string) (bool, error)
DeleteContainer(ctx context.Context, container string) error
}
func (client *blobsClient) BlobExists(ctx context.Context, container string, blobPath string) (bool, error) {
blobRef := client.ServiceClient().NewContainerClient(container).NewBlobClient(blobPath)
_, err := blobRef.GetProperties(ctx, nil)
if err != nil {
if bloberror.HasCode(
err,
bloberror.BlobNotFound,
bloberror.ContainerNotFound,
bloberror.ResourceNotFound,
bloberror.CannotVerifyCopySource,
) {
return false, nil
} else {
return false, err
}
}
return true, nil
}
func (client *blobsClient) DeleteContainer(ctx context.Context, container string) error {
containerRef := client.ServiceClient().NewContainerClient(container)
_, err := containerRef.Delete(ctx, nil)
if err != nil {
if bloberror.HasCode(
err,
bloberror.ContainerNotFound,
bloberror.ResourceNotFound,
) {
return nil
}
}
return err
}

Просмотреть файл

@ -0,0 +1,8 @@
package azblob
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
//go:generate rm -rf ../../../../../mocks/azureclient/azuresdk/$GOPACKAGE
//go:generate mockgen -destination=../../../mocks/azureclient/azuresdk/$GOPACKAGE/blobs.go -source=blobs.go
//go:generate goimports -local=github.com/Azure/ARO-RP -e -w ../../../mocks/azureclient/azuresdk/$GOPACKAGE/blobs.go

Просмотреть файл

@ -1,8 +1,8 @@
package azblob package blob
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0. // Licensed under the Apache License 2.0.
//go:generate rm -rf ../mocks/$GOPACKAGE //go:generate rm -rf ../mocks/$GOPACKAGE
//go:generate mockgen -destination=../mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/$GOPACKAGE Manager,AZBlobClient //go:generate mockgen -destination=../mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/$GOPACKAGE Manager
//go:generate goimports -local=github.com/Azure/ARO-RP -e -w ../mocks/$GOPACKAGE/$GOPACKAGE.go //go:generate goimports -local=github.com/Azure/ARO-RP -e -w ../mocks/$GOPACKAGE/$GOPACKAGE.go

46
pkg/util/blob/manager.go Normal file
Просмотреть файл

@ -0,0 +1,46 @@
package blob
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
azstorage "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armstorage"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azblob"
)
type Manager interface {
GetContainerProperties(ctx context.Context, resourceGroupName string, accountName string, containerName string) (azstorage.AccountsClientGetPropertiesResponse, error)
GetBlobsClient(blobContainerURL string) (azblob.BlobsClient, error)
}
type manager struct {
cred azcore.TokenCredential
account armstorage.AccountsClient
clientOptions *arm.ClientOptions
}
func NewManager(subscriptionID string, credential azcore.TokenCredential, options *arm.ClientOptions) (Manager, error) {
accountsClient, err := armstorage.NewAccountsClient(subscriptionID, credential, options)
if err != nil {
return nil, err
}
return &manager{
cred: credential,
account: accountsClient,
clientOptions: options,
}, nil
}
func (m *manager) GetContainerProperties(ctx context.Context, resourceGroupName string, accountName string, containerName string) (azstorage.AccountsClientGetPropertiesResponse, error) {
return m.account.GetProperties(ctx, resourceGroupName, accountName, &azstorage.AccountsClientGetPropertiesOptions{})
}
func (m *manager) GetBlobsClient(blobContainerURL string) (azblob.BlobsClient, error) {
return azblob.NewBlobsClientUsingEntra(blobContainerURL, m.cred, m.clientOptions)
}

Просмотреть файл

@ -1,9 +1,9 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Azure/ARO-RP/pkg/util/azblob (interfaces: Manager,AZBlobClient) // Source: github.com/Azure/ARO-RP/pkg/util/azblob (interfaces: Manager)
// //
// Generated by this command: // Generated by this command:
// //
// mockgen -destination=../mocks/azblob/azblob.go github.com/Azure/ARO-RP/pkg/util/azblob Manager,AZBlobClient // mockgen -destination=../mocks/azblob/azblob.go github.com/Azure/ARO-RP/pkg/util/azblob Manager
// //
// Package mock_azblob is a generated GoMock package. // Package mock_azblob is a generated GoMock package.
@ -14,10 +14,9 @@ import (
reflect "reflect" reflect "reflect"
armstorage "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" armstorage "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
azblob0 "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
gomock "go.uber.org/mock/gomock" gomock "go.uber.org/mock/gomock"
azblob "github.com/Azure/ARO-RP/pkg/util/azblob" azblob "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azblob"
) )
// MockManager is a mock of Manager interface. // MockManager is a mock of Manager interface.
@ -43,19 +42,19 @@ func (m *MockManager) EXPECT() *MockManagerMockRecorder {
return m.recorder return m.recorder
} }
// GetAZBlobClient mocks base method. // GetBlobClient mocks base method.
func (m *MockManager) GetAZBlobClient(arg0 string, arg1 *azblob0.ClientOptions) (azblob.AZBlobClient, error) { func (m *MockManager) GetBlobClient(arg0 string) (azblob.BlobsClient, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAZBlobClient", arg0, arg1) ret := m.ctrl.Call(m, "GetBlobClient", arg0)
ret0, _ := ret[0].(azblob.AZBlobClient) ret0, _ := ret[0].(azblob.BlobsClient)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// GetAZBlobClient indicates an expected call of GetAZBlobClient. // GetBlobClient indicates an expected call of GetBlobClient.
func (mr *MockManagerMockRecorder) GetAZBlobClient(arg0, arg1 any) *gomock.Call { func (mr *MockManagerMockRecorder) GetBlobClient(arg0 any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAZBlobClient", reflect.TypeOf((*MockManager)(nil).GetAZBlobClient), arg0, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlobClient", reflect.TypeOf((*MockManager)(nil).GetBlobClient), arg0)
} }
// GetContainerProperties mocks base method. // GetContainerProperties mocks base method.
@ -72,54 +71,3 @@ func (mr *MockManagerMockRecorder) GetContainerProperties(arg0, arg1, arg2, arg3
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContainerProperties", reflect.TypeOf((*MockManager)(nil).GetContainerProperties), arg0, arg1, arg2, arg3) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContainerProperties", reflect.TypeOf((*MockManager)(nil).GetContainerProperties), arg0, arg1, arg2, arg3)
} }
// MockAZBlobClient is a mock of AZBlobClient interface.
type MockAZBlobClient struct {
ctrl *gomock.Controller
recorder *MockAZBlobClientMockRecorder
}
// MockAZBlobClientMockRecorder is the mock recorder for MockAZBlobClient.
type MockAZBlobClientMockRecorder struct {
mock *MockAZBlobClient
}
// NewMockAZBlobClient creates a new mock instance.
func NewMockAZBlobClient(ctrl *gomock.Controller) *MockAZBlobClient {
mock := &MockAZBlobClient{ctrl: ctrl}
mock.recorder = &MockAZBlobClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAZBlobClient) EXPECT() *MockAZBlobClientMockRecorder {
return m.recorder
}
// DeleteBlob mocks base method.
func (m *MockAZBlobClient) DeleteBlob(arg0 context.Context, arg1, arg2 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteBlob", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteBlob indicates an expected call of DeleteBlob.
func (mr *MockAZBlobClientMockRecorder) DeleteBlob(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBlob", reflect.TypeOf((*MockAZBlobClient)(nil).DeleteBlob), arg0, arg1, arg2)
}
// UploadBuffer mocks base method.
func (m *MockAZBlobClient) UploadBuffer(arg0 context.Context, arg1, arg2 string, arg3 []byte) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UploadBuffer", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(error)
return ret0
}
// UploadBuffer indicates an expected call of UploadBuffer.
func (mr *MockAZBlobClientMockRecorder) UploadBuffer(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBuffer", reflect.TypeOf((*MockAZBlobClient)(nil).UploadBuffer), arg0, arg1, arg2, arg3)
}

Просмотреть файл

@ -54,3 +54,18 @@ func (mr *MockAccountsClientMockRecorder) GetProperties(arg0, arg1, arg2, arg3 a
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProperties", reflect.TypeOf((*MockAccountsClient)(nil).GetProperties), arg0, arg1, arg2, arg3) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProperties", reflect.TypeOf((*MockAccountsClient)(nil).GetProperties), arg0, arg1, arg2, arg3)
} }
// ListAccountSAS mocks base method.
func (m *MockAccountsClient) ListAccountSAS(arg0 context.Context, arg1, arg2 string, arg3 armstorage.AccountSasParameters, arg4 *armstorage.AccountsClientListAccountSASOptions) (armstorage.AccountsClientListAccountSASResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAccountSAS", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(armstorage.AccountsClientListAccountSASResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ListAccountSAS indicates an expected call of ListAccountSAS.
func (mr *MockAccountsClientMockRecorder) ListAccountSAS(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccountSAS", reflect.TypeOf((*MockAccountsClient)(nil).ListAccountSAS), arg0, arg1, arg2, arg3, arg4)
}

Просмотреть файл

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: blobs.go
//
// Generated by this command:
//
// mockgen -destination=../../../mocks/azureclient/azuresdk/azblob/blobs.go -source=blobs.go
//
// Package mock_azblob is a generated GoMock package.
package mock_azblob
import (
context "context"
reflect "reflect"
azblob "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
gomock "go.uber.org/mock/gomock"
)
// MockBlobsClient is a mock of BlobsClient interface.
type MockBlobsClient struct {
ctrl *gomock.Controller
recorder *MockBlobsClientMockRecorder
}
// MockBlobsClientMockRecorder is the mock recorder for MockBlobsClient.
type MockBlobsClientMockRecorder struct {
mock *MockBlobsClient
}
// NewMockBlobsClient creates a new mock instance.
func NewMockBlobsClient(ctrl *gomock.Controller) *MockBlobsClient {
mock := &MockBlobsClient{ctrl: ctrl}
mock.recorder = &MockBlobsClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockBlobsClient) EXPECT() *MockBlobsClientMockRecorder {
return m.recorder
}
// BlobExists mocks base method.
func (m *MockBlobsClient) BlobExists(ctx context.Context, container, blobPath string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlobExists", ctx, container, blobPath)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BlobExists indicates an expected call of BlobExists.
func (mr *MockBlobsClientMockRecorder) BlobExists(ctx, container, blobPath any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlobExists", reflect.TypeOf((*MockBlobsClient)(nil).BlobExists), ctx, container, blobPath)
}
// DeleteBlob mocks base method.
func (m *MockBlobsClient) DeleteBlob(ctx context.Context, containerName, blobName string, o *azblob.DeleteBlobOptions) (azblob.DeleteBlobResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteBlob", ctx, containerName, blobName, o)
ret0, _ := ret[0].(azblob.DeleteBlobResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DeleteBlob indicates an expected call of DeleteBlob.
func (mr *MockBlobsClientMockRecorder) DeleteBlob(ctx, containerName, blobName, o any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBlob", reflect.TypeOf((*MockBlobsClient)(nil).DeleteBlob), ctx, containerName, blobName, o)
}
// DeleteContainer mocks base method.
func (m *MockBlobsClient) DeleteContainer(ctx context.Context, container string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteContainer", ctx, container)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteContainer indicates an expected call of DeleteContainer.
func (mr *MockBlobsClientMockRecorder) DeleteContainer(ctx, container any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteContainer", reflect.TypeOf((*MockBlobsClient)(nil).DeleteContainer), ctx, container)
}
// DownloadStream mocks base method.
func (m *MockBlobsClient) DownloadStream(ctx context.Context, containerName, blobName string, o *azblob.DownloadStreamOptions) (azblob.DownloadStreamResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DownloadStream", ctx, containerName, blobName, o)
ret0, _ := ret[0].(azblob.DownloadStreamResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DownloadStream indicates an expected call of DownloadStream.
func (mr *MockBlobsClientMockRecorder) DownloadStream(ctx, containerName, blobName, o any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadStream", reflect.TypeOf((*MockBlobsClient)(nil).DownloadStream), ctx, containerName, blobName, o)
}
// UploadBuffer mocks base method.
func (m *MockBlobsClient) UploadBuffer(ctx context.Context, containerName, blobName string, buffer []byte, o *azblob.UploadBufferOptions) (azblob.UploadBufferResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UploadBuffer", ctx, containerName, blobName, buffer, o)
ret0, _ := ret[0].(azblob.UploadBufferResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// UploadBuffer indicates an expected call of UploadBuffer.
func (mr *MockBlobsClientMockRecorder) UploadBuffer(ctx, containerName, blobName, buffer, o any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBuffer", reflect.TypeOf((*MockBlobsClient)(nil).UploadBuffer), ctx, containerName, blobName, buffer, o)
}

Просмотреть файл

@ -0,0 +1,73 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Azure/ARO-RP/pkg/util/blob (interfaces: Manager)
//
// Generated by this command:
//
// mockgen -destination=../mocks/blob/blob.go github.com/Azure/ARO-RP/pkg/util/blob Manager
//
// Package mock_blob is a generated GoMock package.
package mock_blob
import (
context "context"
reflect "reflect"
armstorage "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
gomock "go.uber.org/mock/gomock"
azblob "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azblob"
)
// MockManager is a mock of Manager interface.
type MockManager struct {
ctrl *gomock.Controller
recorder *MockManagerMockRecorder
}
// MockManagerMockRecorder is the mock recorder for MockManager.
type MockManagerMockRecorder struct {
mock *MockManager
}
// NewMockManager creates a new mock instance.
func NewMockManager(ctrl *gomock.Controller) *MockManager {
mock := &MockManager{ctrl: ctrl}
mock.recorder = &MockManagerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockManager) EXPECT() *MockManagerMockRecorder {
return m.recorder
}
// GetBlobsClient mocks base method.
func (m *MockManager) GetBlobsClient(arg0 string) (azblob.BlobsClient, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBlobsClient", arg0)
ret0, _ := ret[0].(azblob.BlobsClient)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBlobsClient indicates an expected call of GetBlobsClient.
func (mr *MockManagerMockRecorder) GetBlobsClient(arg0 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlobsClient", reflect.TypeOf((*MockManager)(nil).GetBlobsClient), arg0)
}
// GetContainerProperties mocks base method.
func (m *MockManager) GetContainerProperties(arg0 context.Context, arg1, arg2, arg3 string) (armstorage.AccountsClientGetPropertiesResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetContainerProperties", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(armstorage.AccountsClientGetPropertiesResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetContainerProperties indicates an expected call of GetContainerProperties.
func (mr *MockManagerMockRecorder) GetContainerProperties(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContainerProperties", reflect.TypeOf((*MockManager)(nil).GetContainerProperties), arg0, arg1, arg2, arg3)
}

Просмотреть файл

@ -1,9 +1,9 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Azure/ARO-RP/pkg/util/storage (interfaces: BlobStorageClient,Manager) // Source: github.com/Azure/ARO-RP/pkg/util/storage (interfaces: Manager)
// //
// Generated by this command: // Generated by this command:
// //
// mockgen -destination=../mocks/storage/storage.go github.com/Azure/ARO-RP/pkg/util/storage BlobStorageClient,Manager // mockgen -destination=../mocks/storage/storage.go github.com/Azure/ARO-RP/pkg/util/storage Manager
// //
// Package mock_storage is a generated GoMock package. // Package mock_storage is a generated GoMock package.
@ -11,68 +11,14 @@ package mock_storage
import ( import (
context "context" context "context"
io "io"
reflect "reflect" reflect "reflect"
storage0 "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage" armstorage "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
storage1 "github.com/Azure/azure-sdk-for-go/storage"
gomock "go.uber.org/mock/gomock" gomock "go.uber.org/mock/gomock"
storage "github.com/Azure/ARO-RP/pkg/util/storage" azblob "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azblob"
) )
// MockBlobStorageClient is a mock of BlobStorageClient interface.
type MockBlobStorageClient struct {
ctrl *gomock.Controller
recorder *MockBlobStorageClientMockRecorder
}
// MockBlobStorageClientMockRecorder is the mock recorder for MockBlobStorageClient.
type MockBlobStorageClientMockRecorder struct {
mock *MockBlobStorageClient
}
// NewMockBlobStorageClient creates a new mock instance.
func NewMockBlobStorageClient(ctrl *gomock.Controller) *MockBlobStorageClient {
mock := &MockBlobStorageClient{ctrl: ctrl}
mock.recorder = &MockBlobStorageClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockBlobStorageClient) EXPECT() *MockBlobStorageClientMockRecorder {
return m.recorder
}
// Get mocks base method.
func (m *MockBlobStorageClient) Get(arg0 string) (io.ReadCloser, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(io.ReadCloser)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockBlobStorageClientMockRecorder) Get(arg0 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockBlobStorageClient)(nil).Get), arg0)
}
// GetContainerReference mocks base method.
func (m *MockBlobStorageClient) GetContainerReference(arg0 string) *storage1.Container {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetContainerReference", arg0)
ret0, _ := ret[0].(*storage1.Container)
return ret0
}
// GetContainerReference indicates an expected call of GetContainerReference.
func (mr *MockBlobStorageClientMockRecorder) GetContainerReference(arg0 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContainerReference", reflect.TypeOf((*MockBlobStorageClient)(nil).GetContainerReference), arg0)
}
// MockManager is a mock of Manager interface. // MockManager is a mock of Manager interface.
type MockManager struct { type MockManager struct {
ctrl *gomock.Controller ctrl *gomock.Controller
@ -97,10 +43,10 @@ func (m *MockManager) EXPECT() *MockManagerMockRecorder {
} }
// BlobService mocks base method. // BlobService mocks base method.
func (m *MockManager) BlobService(arg0 context.Context, arg1, arg2 string, arg3 storage0.Permissions, arg4 storage0.SignedResourceTypes) (storage.BlobStorageClient, error) { func (m *MockManager) BlobService(arg0 context.Context, arg1, arg2 string, arg3 armstorage.Permissions, arg4 armstorage.SignedResourceTypes) (azblob.BlobsClient, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BlobService", arg0, arg1, arg2, arg3, arg4) ret := m.ctrl.Call(m, "BlobService", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(storage.BlobStorageClient) ret0, _ := ret[0].(azblob.BlobsClient)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }

Просмотреть файл

@ -7,7 +7,6 @@ import (
"go.uber.org/mock/gomock" "go.uber.org/mock/gomock"
mock_azblob "github.com/Azure/ARO-RP/pkg/util/mocks/azblob"
utilerror "github.com/Azure/ARO-RP/test/util/error" utilerror "github.com/Azure/ARO-RP/test/util/error"
) )
@ -29,7 +28,6 @@ func TestKeyIDFromPublicKey(t *testing.T) {
for _, tt := range []struct { for _, tt := range []struct {
name string name string
mocks func(*mock_azblob.MockAZBlobClient)
publicKey interface{} publicKey interface{}
wantkid string wantkid string
wantErr string wantErr string

Просмотреть файл

@ -10,7 +10,7 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/ARO-RP/pkg/env" "github.com/Azure/ARO-RP/pkg/env"
utilazblob "github.com/Azure/ARO-RP/pkg/util/azblob" "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azblob"
) )
const ( const (
@ -46,7 +46,7 @@ func GenerateBlobContainerURL(env env.Interface) string {
return fmt.Sprintf("https://%s.blob.%s/%s", env.OIDCStorageAccountName(), env.Environment().StorageEndpointSuffix, WebContainer) return fmt.Sprintf("https://%s.blob.%s/%s", env.OIDCStorageAccountName(), env.Environment().StorageEndpointSuffix, WebContainer)
} }
func (b *OIDCBuilder) EnsureOIDCDocs(ctx context.Context, azBlobClient utilazblob.AZBlobClient) error { func (b *OIDCBuilder) EnsureOIDCDocs(ctx context.Context, blobsClient azblob.BlobsClient) error {
// Create the OIDC configuration // Create the OIDC configuration
discoveryDocument := GenerateDiscoveryDocument(b.endpointURL) discoveryDocument := GenerateDiscoveryDocument(b.endpointURL)
@ -56,7 +56,7 @@ func (b *OIDCBuilder) EnsureOIDCDocs(ctx context.Context, azBlobClient utilazblo
return err return err
} }
return populateOidcFolder(ctx, b.directory, discoveryDocument, jwks, azBlobClient) return populateOidcFolder(ctx, b.directory, discoveryDocument, jwks, blobsClient)
} }
func (b *OIDCBuilder) GetEndpointUrl() string { func (b *OIDCBuilder) GetEndpointUrl() string {
@ -71,28 +71,31 @@ func (b *OIDCBuilder) GetBlobContainerURL() string {
return b.blobContainerURL return b.blobContainerURL
} }
func populateOidcFolder(ctx context.Context, directory string, discoveryDocument string, jwks []byte, azBlobClient utilazblob.AZBlobClient) error { func populateOidcFolder(ctx context.Context, directory string, discoveryDocument string, jwks []byte, blobsClient azblob.BlobsClient) error {
err := azBlobClient.UploadBuffer( _, err := blobsClient.UploadBuffer(
ctx, ctx,
"", "",
DocumentKey(directory, DiscoveryDocumentKey), DocumentKey(directory, DiscoveryDocumentKey),
[]byte(discoveryDocument), []byte(discoveryDocument),
nil,
) )
if err != nil { if err != nil {
return err return err
} }
return azBlobClient.UploadBuffer( _, err = blobsClient.UploadBuffer(
ctx, ctx,
"", "",
DocumentKey(directory, JWKSKey), DocumentKey(directory, JWKSKey),
jwks, jwks,
nil,
) )
return err
} }
func DeleteOidcFolder(ctx context.Context, directory string, azBlobClient utilazblob.AZBlobClient) error { func DeleteOidcFolder(ctx context.Context, directory string, blobsClient azblob.BlobsClient) error {
for _, key := range []string{DiscoveryDocumentKey, JWKSKey} { for _, key := range []string{DiscoveryDocumentKey, JWKSKey} {
err := azBlobClient.DeleteBlob(ctx, "", DocumentKey(directory, key)) _, err := blobsClient.DeleteBlob(ctx, "", DocumentKey(directory, key), nil)
if err != nil && !bloberror.HasCode(err, bloberror.BlobNotFound) { if err != nil && !bloberror.HasCode(err, bloberror.BlobNotFound) {
return err return err
} }

Просмотреть файл

@ -9,7 +9,6 @@ import (
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -18,11 +17,13 @@ import (
"testing" "testing"
"github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/pkg/errors"
"go.uber.org/mock/gomock" "go.uber.org/mock/gomock"
"github.com/Azure/ARO-RP/pkg/util/azureclient" "github.com/Azure/ARO-RP/pkg/util/azureclient"
mock_azblob "github.com/Azure/ARO-RP/pkg/util/mocks/azblob" mock_azblob "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/azuresdk/azblob"
mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env" mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env"
utilerror "github.com/Azure/ARO-RP/test/util/error" utilerror "github.com/Azure/ARO-RP/test/util/error"
) )
@ -47,10 +48,11 @@ func TestEnsureOIDCDocs(t *testing.T) {
}) })
invalidKey := []byte("Invalid Key") invalidKey := []byte("Invalid Key")
uploadResponse := azblob.UploadBufferResponse{}
for _, tt := range []struct { for _, tt := range []struct {
name string name string
mocks func(*mock_azblob.MockAZBlobClient) mocks func(*mock_azblob.MockBlobsClient)
oidcbuilder *OIDCBuilder oidcbuilder *OIDCBuilder
wantErr string wantErr string
}{ }{
@ -63,13 +65,13 @@ func TestEnsureOIDCDocs(t *testing.T) {
directory: directoryName, directory: directoryName,
endpointURL: endpointURL, endpointURL: endpointURL,
}, },
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT(). blobsClient.EXPECT().
UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, DiscoveryDocumentKey), gomock.Any()). UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, DiscoveryDocumentKey), gomock.Any(), nil).
Return(nil) Return(uploadResponse, nil)
azblobClient.EXPECT(). blobsClient.EXPECT().
UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, JWKSKey), gomock.Any()). UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, JWKSKey), gomock.Any(), nil).
Return(nil) Return(uploadResponse, nil)
}, },
}, },
{ {
@ -103,10 +105,10 @@ func TestEnsureOIDCDocs(t *testing.T) {
endpointURL: endpointURL, endpointURL: endpointURL,
directory: directoryName, directory: directoryName,
}, },
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT(). blobsClient.EXPECT().
UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, DiscoveryDocumentKey), gomock.Any()). UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, DiscoveryDocumentKey), gomock.Any(), nil).
Return(errors.New("generic error")) Return(uploadResponse, errors.New("generic error"))
}, },
wantErr: "generic error", wantErr: "generic error",
}, },
@ -119,13 +121,13 @@ func TestEnsureOIDCDocs(t *testing.T) {
endpointURL: endpointURL, endpointURL: endpointURL,
directory: directoryName, directory: directoryName,
}, },
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT(). blobsClient.EXPECT().
UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, DiscoveryDocumentKey), gomock.Any()). UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, DiscoveryDocumentKey), gomock.Any(), nil).
Return(nil) Return(uploadResponse, nil)
azblobClient.EXPECT(). blobsClient.EXPECT().
UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, JWKSKey), gomock.Any()). UploadBuffer(gomock.Any(), "", DocumentKey(directoryName, JWKSKey), gomock.Any(), nil).
Return(errors.New("generic error")) Return(uploadResponse, errors.New("generic error"))
}, },
wantErr: "generic error", wantErr: "generic error",
}, },
@ -145,13 +147,13 @@ func TestEnsureOIDCDocs(t *testing.T) {
controller := gomock.NewController(t) controller := gomock.NewController(t)
defer controller.Finish() defer controller.Finish()
azBlobClient := mock_azblob.NewMockAZBlobClient(controller) blobsClient := mock_azblob.NewMockBlobsClient(controller)
if tt.mocks != nil { if tt.mocks != nil {
tt.mocks(azBlobClient) tt.mocks(blobsClient)
} }
err = tt.oidcbuilder.EnsureOIDCDocs(ctx, azBlobClient) err = tt.oidcbuilder.EnsureOIDCDocs(ctx, blobsClient)
utilerror.AssertErrorMessage(t, err, tt.wantErr) utilerror.AssertErrorMessage(t, err, tt.wantErr)
if tt.oidcbuilder.GetEndpointUrl() != tt.oidcbuilder.endpointURL { if tt.oidcbuilder.GetEndpointUrl() != tt.oidcbuilder.endpointURL {
@ -226,39 +228,40 @@ ERROR CODE: Generic Error
Generic Error Generic Error
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
` `
deleteResponse := azblob.DeleteBlobResponse{}
for _, tt := range []struct { for _, tt := range []struct {
name string name string
mocks func(*mock_azblob.MockAZBlobClient) mocks func(*mock_azblob.MockBlobsClient)
wantErr string wantErr string
}{ }{
{ {
name: "Success", name: "Success",
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey)).Return(nil) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey), nil).Return(deleteResponse, nil)
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, JWKSKey)).Return(nil) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, JWKSKey), nil).Return(deleteResponse, nil)
}, },
}, },
{ {
name: "Fail - Generic Error when deleting DiscoveryDocument", name: "Fail - Generic Error when deleting DiscoveryDocument",
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey)).Return(respErrGeneric) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey), nil).Return(deleteResponse, respErrGeneric)
}, },
wantErr: genericErrorMessage, wantErr: genericErrorMessage,
}, },
{ {
name: "Fail - Generic Error when deleting JWKS", name: "Fail - Generic Error when deleting JWKS",
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey)).Return(respErrBlobNotFound) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey), nil).Return(deleteResponse, respErrBlobNotFound)
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, JWKSKey)).Return(respErrGeneric) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, JWKSKey), nil).Return(deleteResponse, respErrGeneric)
}, },
wantErr: genericErrorMessage, wantErr: genericErrorMessage,
}, },
{ {
name: "Success - One Blob exists and other doesn't", name: "Success - One Blob exists and other doesn't",
mocks: func(azblobClient *mock_azblob.MockAZBlobClient) { mocks: func(blobsClient *mock_azblob.MockBlobsClient) {
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey)).Return(respErrBlobNotFound) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, DiscoveryDocumentKey), nil).Return(deleteResponse, respErrBlobNotFound)
azblobClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, JWKSKey)).Return(nil) blobsClient.EXPECT().DeleteBlob(ctx, "", DocumentKey(directoryName, JWKSKey), nil).Return(deleteResponse, nil)
}, },
}, },
} { } {
@ -266,13 +269,13 @@ Generic Error
controller := gomock.NewController(t) controller := gomock.NewController(t)
defer controller.Finish() defer controller.Finish()
azBlobClient := mock_azblob.NewMockAZBlobClient(controller) blobsClient := mock_azblob.NewMockBlobsClient(controller)
if tt.mocks != nil { if tt.mocks != nil {
tt.mocks(azBlobClient) tt.mocks(blobsClient)
} }
err := DeleteOidcFolder(ctx, directoryName, azBlobClient) err := DeleteOidcFolder(ctx, directoryName, blobsClient)
utilerror.AssertErrorMessage(t, err, tt.wantErr) utilerror.AssertErrorMessage(t, err, tt.wantErr)
}) })
} }

Просмотреть файл

@ -35,7 +35,7 @@ func NewPlatformWorkloadIdentityRolesByVersionService() *PlatformWorkloadIdentit
// PopulatePlatformWorkloadIdentityRolesByVersion aims to populate platformWorkloadIdentityRoles for current OpenShift minor version and also for UpgradeableTo minor version if provided and is greater than the current version // PopulatePlatformWorkloadIdentityRolesByVersion aims to populate platformWorkloadIdentityRoles for current OpenShift minor version and also for UpgradeableTo minor version if provided and is greater than the current version
func (service *PlatformWorkloadIdentityRolesByVersionService) PopulatePlatformWorkloadIdentityRolesByVersion(ctx context.Context, oc *api.OpenShiftCluster, dbPlatformWorkloadIdentityRoleSets database.PlatformWorkloadIdentityRoleSets) error { func (service *PlatformWorkloadIdentityRolesByVersionService) PopulatePlatformWorkloadIdentityRolesByVersion(ctx context.Context, oc *api.OpenShiftCluster, dbPlatformWorkloadIdentityRoleSets database.PlatformWorkloadIdentityRoleSets) error {
if !oc.UsesWorkloadIdentity() { if !oc.UsesWorkloadIdentity() {
return fmt.Errorf("PopulatePlatformWorkloadIdentityRolesByVersion called for a CSP cluster") return fmt.Errorf("PopulatePlatformWorkloadIdentityRolesByVersion called for a Cluster Service Principal cluster")
} }
currentOpenShiftVersion, err := version.ParseVersion(oc.Properties.ClusterProfile.Version) currentOpenShiftVersion, err := version.ParseVersion(oc.Properties.ClusterProfile.Version)
if err != nil { if err != nil {

Просмотреть файл

@ -34,14 +34,14 @@ func TestNewPlatformWorkloadIdentityRolesByVersion(t *testing.T) {
}, },
}, },
}, },
wantErr: "PopulatePlatformWorkloadIdentityRolesByVersion called for a CSP cluster", wantErr: "PopulatePlatformWorkloadIdentityRolesByVersion called for a Cluster Service Principal cluster",
}, },
{ {
name: "Fail - Exit the func for non MIWI clusters that has no PlatformWorkloadIdentityProfile or ServicePrincipalProfile", name: "Fail - Exit the func for non MIWI clusters that has no PlatformWorkloadIdentityProfile or ServicePrincipalProfile",
oc: &api.OpenShiftCluster{ oc: &api.OpenShiftCluster{
Properties: api.OpenShiftClusterProperties{}, Properties: api.OpenShiftClusterProperties{},
}, },
wantErr: "PopulatePlatformWorkloadIdentityRolesByVersion called for a CSP cluster", wantErr: "PopulatePlatformWorkloadIdentityRolesByVersion called for a Cluster Service Principal cluster",
}, },
{ {
name: "Success - The role set document found for the cluster version", name: "Success - The role set document found for the cluster version",

Просмотреть файл

@ -4,5 +4,5 @@ package storage
// Licensed under the Apache License 2.0. // Licensed under the Apache License 2.0.
//go:generate rm -rf ../mocks/$GOPACKAGE //go:generate rm -rf ../mocks/$GOPACKAGE
//go:generate mockgen -destination=../mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/$GOPACKAGE BlobStorageClient,Manager //go:generate mockgen -destination=../mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/$GOPACKAGE Manager
//go:generate goimports -local=github.com/Azure/ARO-RP -e -w ../mocks/$GOPACKAGE/$GOPACKAGE.go //go:generate goimports -local=github.com/Azure/ARO-RP -e -w ../mocks/$GOPACKAGE/$GOPACKAGE.go

Просмотреть файл

@ -5,49 +5,56 @@ package storage
import ( import (
"context" "context"
"io" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"strings"
"time" "time"
mgmtstorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
azstorage "github.com/Azure/azure-sdk-for-go/storage" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/go-autorest/autorest" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/go-autorest/autorest/date" storagesdk "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/ARO-RP/pkg/api" "github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/env" "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armstorage"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/storage" "github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azblob"
) )
type BlobStorageClient interface {
Get(uri string) (io.ReadCloser, error)
GetContainerReference(name string) *azstorage.Container
}
type Manager interface { type Manager interface {
BlobService(ctx context.Context, resourceGroup, account string, p mgmtstorage.Permissions, r mgmtstorage.SignedResourceTypes) (BlobStorageClient, error) BlobService(ctx context.Context, resourceGroup, account string, p storagesdk.Permissions, r storagesdk.SignedResourceTypes) (azblob.BlobsClient, error)
} }
type manager struct { type manager struct {
env env.Core storageAccounts armstorage.AccountsClient
storageAccounts storage.AccountsClient credential azcore.TokenCredential
usesWorkloadIdentity bool
storageEndpointSuffix string
clientOptions *arm.ClientOptions
} }
func NewManager(env env.Core, subscriptionID string, authorizer autorest.Authorizer) Manager { func NewManager(subscriptionID, storageEndpointSuffix string, credential azcore.TokenCredential, usesWorkloadIdentity bool, options *arm.ClientOptions) (m Manager, err error) {
return &manager{ var accountsClient armstorage.AccountsClient
env: env, if !usesWorkloadIdentity {
storageAccounts: storage.NewAccountsClient(env.Environment(), subscriptionID, authorizer), accountsClient, err = armstorage.NewAccountsClient(subscriptionID, credential, options)
if err != nil {
return nil, err
}
} }
return &manager{
storageAccounts: accountsClient,
usesWorkloadIdentity: usesWorkloadIdentity,
credential: credential,
storageEndpointSuffix: storageEndpointSuffix,
clientOptions: options,
}, nil
} }
func getCorrectErrWhenTooManyRequests(err error) error { func getCorrectErrWhenTooManyRequests(err error) error {
detailedError, ok := err.(autorest.DetailedError) responseError, ok := err.(*azcore.ResponseError)
if !ok { if !ok {
return err return err
} }
if detailedError.StatusCode != http.StatusTooManyRequests { if responseError.StatusCode != http.StatusTooManyRequests {
return err return err
} }
msg := "Requests are being throttled due to Azure Storage limits being exceeded. Please visit https://learn.microsoft.com/en-us/azure/openshift/troubleshoot#exceeding-azure-storage-limits for more details." msg := "Requests are being throttled due to Azure Storage limits being exceeded. Please visit https://learn.microsoft.com/en-us/azure/openshift/troubleshoot#exceeding-azure-storage-limits for more details."
@ -66,43 +73,30 @@ func getCorrectErrWhenTooManyRequests(err error) error {
return cloudError return cloudError
} }
func (m *manager) BlobService(ctx context.Context, resourceGroup, account string, p mgmtstorage.Permissions, r mgmtstorage.SignedResourceTypes) (BlobStorageClient, error) { func (m *manager) BlobService(ctx context.Context, resourceGroup, account string, p storagesdk.Permissions, r storagesdk.SignedResourceTypes) (blobsClient azblob.BlobsClient, err error) {
serviceURL := fmt.Sprintf("https://%s.blob.%s", account, m.storageEndpointSuffix)
if m.usesWorkloadIdentity {
return azblob.NewBlobsClientUsingEntra(serviceURL, m.credential, m.clientOptions)
}
t := time.Now().UTC().Truncate(time.Second) t := time.Now().UTC().Truncate(time.Second)
res, err := m.storageAccounts.ListAccountSAS(ctx, resourceGroup, account, mgmtstorage.AccountSasParameters{ res, err := m.storageAccounts.ListAccountSAS(ctx, resourceGroup, account, storagesdk.AccountSasParameters{
Services: mgmtstorage.ServicesB, Services: to.Ptr(storagesdk.ServicesB),
ResourceTypes: r, ResourceTypes: to.Ptr(r),
Permissions: p, Permissions: to.Ptr(p),
Protocols: mgmtstorage.HTTPProtocolHTTPS, Protocols: to.Ptr(storagesdk.HTTPProtocolHTTPS),
SharedAccessStartTime: &date.Time{Time: t}, SharedAccessStartTime: &t,
SharedAccessExpiryTime: &date.Time{Time: t.Add(24 * time.Hour)}, SharedAccessExpiryTime: to.Ptr(t.Add(24 * time.Hour)),
}) }, nil)
if err != nil { if err != nil {
return nil, getCorrectErrWhenTooManyRequests(err) return nil, getCorrectErrWhenTooManyRequests(err)
} }
v, err := url.ParseQuery(*res.AccountSasToken) _, err = url.ParseQuery(*res.AccountSasToken)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blobcli := azstorage.NewAccountSASClient(account, v, (*m.env.Environment()).Environment).GetBlobService() sasURL := fmt.Sprintf("%s/?%s", serviceURL, *res.AccountSasToken)
return azblob.NewBlobsClientUsingSAS(sasURL, m.clientOptions)
return &wrappedStorageClient{&blobcli}, nil
}
type wrappedStorageClient struct {
client *azstorage.BlobStorageClient
}
func (c *wrappedStorageClient) GetContainerReference(name string) *azstorage.Container {
return c.client.GetContainerReference(name)
}
func (c *wrappedStorageClient) Get(uri string) (io.ReadCloser, error) {
parts := strings.Split(uri, "/")
container := c.client.GetContainerReference(parts[1])
b := container.GetBlobReference(parts[2])
return b.Get(nil)
} }