Skip to content

Commit

Permalink
Merge pull request #935 from jpflueger/cosmosdb-secret-output
Browse files Browse the repository at this point in the history
saving cosmosdb keys as secrets
  • Loading branch information
Justin Pflueger authored Apr 20, 2020
2 parents dac4cb2 + 1354bf1 commit 5b9018f
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 143 deletions.
9 changes: 5 additions & 4 deletions api/v1alpha1/cosmosdb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ type CosmosDBSpec struct {

// +kubebuilder:validation:MinLength=0

Location string `json:"location,omitempty"`
ResourceGroup string `json:"resourceGroup"`
Kind CosmosDBKind `json:"kind,omitempty"`
Properties CosmosDBProperties `json:"properties,omitempty"`
Location string `json:"location,omitempty"`
ResourceGroup string `json:"resourceGroup"`
Kind CosmosDBKind `json:"kind,omitempty"`
Properties CosmosDBProperties `json:"properties,omitempty"`
KeyVaultToStoreSecrets string `json:"keyVaultToStoreSecrets,omitempty"`
}

// CosmosDBKind enumerates the values for kind.
Expand Down
4 changes: 4 additions & 0 deletions config/samples/azure_v1alpha1_cosmosdb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ spec:
resourceGroup: resourcegroup-azure-operators
properties:
databaseAccountOfferType: Standard

# Use the field below to optionally specify a different keyvault
# to store the connectiong string secrets in
#keyVaultToStoreSecrets: asoSecretKeyVault
29 changes: 22 additions & 7 deletions controllers/cosmosdb_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,27 @@ import (
"testing"

"github.com/Azure/azure-service-operator/api/v1alpha1"
"github.com/Azure/azure-service-operator/pkg/errhelp"

"github.com/stretchr/testify/assert"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

func TestCosmosDBHappyPath(t *testing.T) {
t.Parallel()
defer PanicRecover(t)
ctx := context.Background()
assert := assert.New(t)

cosmosDBAccountName := GenerateTestResourceNameWithRandom("cosmosdb", 8)
cosmosDBNamespace := "default"
name := GenerateTestResourceNameWithRandom("cosmosdb", 8)
namespace := "default"

dbInstance := &v1alpha1.CosmosDB{
ObjectMeta: metav1.ObjectMeta{
Name: cosmosDBAccountName,
Namespace: cosmosDBNamespace,
Name: name,
Namespace: namespace,
},
Spec: v1alpha1.CosmosDBSpec{
Location: tc.resourceGroupLocation,
Expand All @@ -37,10 +42,22 @@ func TestCosmosDBHappyPath(t *testing.T) {
},
}

key := types.NamespacedName{Name: name, Namespace: namespace}

EnsureInstance(ctx, t, tc, dbInstance)

assert.Eventually(func() bool {
secret, err := tc.secretClient.Get(ctx, key)
return err == nil && len(secret) > 0
}, tc.timeoutFast, tc.retry, "wait for cosmosdb to have secret")

EnsureDelete(ctx, t, tc, dbInstance)

assert.Eventually(func() bool {
_, err := tc.secretClient.Get(ctx, key)
return err != nil
}, tc.timeoutFast, tc.retry, "wait for cosmosdb to delete secret")

}

func TestCosmosDBControllerNoResourceGroup(t *testing.T) {
Expand Down Expand Up @@ -69,10 +86,8 @@ func TestCosmosDBControllerNoResourceGroup(t *testing.T) {
},
},
}
//the expected error meessage to be shown
errMessage := "Waiting for resource group '" + resourceGroupName + "' to be available"

EnsureInstanceWithResult(ctx, t, tc, dbInstance1, errMessage, false)
EnsureInstanceWithResult(ctx, t, tc, dbInstance1, errhelp.ResourceGroupNotFoundErrorCode, false)
EnsureDelete(ctx, t, tc, dbInstance1)
}

Expand Down
2 changes: 1 addition & 1 deletion controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func setup() error {
secretClient,
scheme.Scheme,
)
cosmosDbManager = resourcemanagercosmosdb.NewAzureCosmosDBManager()
cosmosDbManager = resourcemanagercosmosdb.NewAzureCosmosDBManager(secretClient)
apiMgmtManager = resourcemanagerapimgmt.NewManager()
resourceGroupManager = resourcegroupsresourcemanager.NewAzureResourceGroupManager()
eventHubManagers = resourcemanagereventhub.AzureEventHubManagers
Expand Down
5 changes: 4 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ func main() {
)
eventhubNamespaceClient := resourcemanagereventhub.NewEventHubNamespaceClient()
consumerGroupClient := resourcemanagereventhub.NewConsumerGroupClient()
cosmosDBClient := resourcemanagercosmosdb.NewAzureCosmosDBManager(
secretClient,
)
storageManagers := resourcemanagerstorage.AzureStorageManagers
keyVaultManager := resourcemanagerkeyvault.NewAzureKeyVaultManager(mgr.GetScheme())
keyVaultKeyManager := &resourcemanagerkeyvault.KeyvaultKeyClient{
Expand Down Expand Up @@ -172,7 +175,7 @@ func main() {
err = (&controllers.CosmosDBReconciler{
Reconciler: &controllers.AsyncReconciler{
Client: mgr.GetClient(),
AzureClient: resourcemanagercosmosdb.NewAzureCosmosDBManager(),
AzureClient: cosmosDBClient,
Telemetry: telemetry.InitializeTelemetryDefault(
"CosmosDB",
ctrl.Log.WithName("controllers").WithName("CosmosDB"),
Expand Down
1 change: 1 addition & 0 deletions pkg/errhelp/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
NotFoundErrorCode = "NotFound"
NoSuchHost = "no such host"
ParentNotFoundErrorCode = "ParentResourceNotFound"
PreconditionFailed = "PreconditionFailed"
QuotaExceeded = "QuotaExceeded"
ResourceGroupNotFoundErrorCode = "ResourceGroupNotFound"
RegionDoesNotAllowProvisioning = "RegionDoesNotAllowProvisioning"
Expand Down
56 changes: 38 additions & 18 deletions pkg/resourcemanager/cosmosdbs/cosmosdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import (

"github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2015-04-08/documentdb"
"github.com/Azure/azure-service-operator/api/v1alpha1"
"github.com/Azure/azure-service-operator/pkg/errhelp"
"github.com/Azure/azure-service-operator/pkg/resourcemanager/config"
"github.com/Azure/azure-service-operator/pkg/resourcemanager/iam"
"github.com/Azure/azure-service-operator/pkg/secrets"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/to"
)

// AzureCosmosDBManager is the struct which contains helper functions for resource groups
type AzureCosmosDBManager struct{}
type AzureCosmosDBManager struct {
SecretClient secrets.SecretClient
}

func getCosmosDBClient() (documentdb.DatabaseAccountsClient, error) {
cosmosDBClient := documentdb.NewDatabaseAccountsClientWithBaseURI(config.BaseURI(), config.SubscriptionID())
Expand All @@ -28,9 +30,9 @@ func getCosmosDBClient() (documentdb.DatabaseAccountsClient, error) {
cosmosDBClient = documentdb.DatabaseAccountsClient{}
} else {
cosmosDBClient.Authorizer = a
cosmosDBClient.AddToUserAgent(config.UserAgent())
}

err = cosmosDBClient.AddToUserAgent(config.UserAgent())
return cosmosDBClient, err
}

Expand All @@ -42,10 +44,10 @@ func (*AzureCosmosDBManager) CreateOrUpdateCosmosDB(
location string,
kind v1alpha1.CosmosDBKind,
dbType v1alpha1.CosmosDBDatabaseAccountOfferType,
tags map[string]*string) (*documentdb.DatabaseAccount, *errhelp.AzureError) {
tags map[string]*string) (*documentdb.DatabaseAccount, error) {
cosmosDBClient, err := getCosmosDBClient()
if err != nil {
return nil, errhelp.NewAzureErrorAzureError(err)
return nil, err
}

dbKind := documentdb.DatabaseAccountKind(kind)
Expand Down Expand Up @@ -91,13 +93,13 @@ func (*AzureCosmosDBManager) CreateOrUpdateCosmosDB(

if err != nil {
// initial create request failed, wrap error
return nil, errhelp.NewAzureErrorAzureError(err)
return nil, err
}

result, err := createUpdateFuture.Result(cosmosDBClient)
if err != nil {
// there is no immediate result, wrap error
return &result, errhelp.NewAzureErrorAzureError(err)
return &result, err
}
return &result, nil
}
Expand All @@ -106,31 +108,31 @@ func (*AzureCosmosDBManager) CreateOrUpdateCosmosDB(
func (*AzureCosmosDBManager) GetCosmosDB(
ctx context.Context,
groupName string,
cosmosDBName string) (*documentdb.DatabaseAccount, *errhelp.AzureError) {
cosmosDBName string) (*documentdb.DatabaseAccount, error) {
cosmosDBClient, err := getCosmosDBClient()
if err != nil {
return nil, errhelp.NewAzureErrorAzureError(err)
return nil, err
}

result, err := cosmosDBClient.Get(ctx, groupName, cosmosDBName)
if err != nil {
return &result, errhelp.NewAzureErrorAzureError(err)
return &result, err
}
return &result, nil
}

// CheckNameExistsCosmosDB checks if the global account name already exists
func (*AzureCosmosDBManager) CheckNameExistsCosmosDB(
ctx context.Context,
accountName string) (bool, *errhelp.AzureError) {
accountName string) (bool, error) {
cosmosDBClient, err := getCosmosDBClient()
if err != nil {
return false, errhelp.NewAzureErrorAzureError(err)
return false, err
}

response, err := cosmosDBClient.CheckNameExists(ctx, accountName)
if err != nil {
return false, errhelp.NewAzureErrorAzureError(err)
return false, err
}

switch response.StatusCode {
Expand All @@ -139,28 +141,46 @@ func (*AzureCosmosDBManager) CheckNameExistsCosmosDB(
case http.StatusOK:
return true, nil
default:
return false, errhelp.NewAzureErrorAzureError(fmt.Errorf("unhandled status code for CheckNameExists"))
return false, fmt.Errorf("unhandled status code for CheckNameExists")
}
}

// DeleteCosmosDB removes the resource group named by env var
func (*AzureCosmosDBManager) DeleteCosmosDB(
ctx context.Context,
groupName string,
cosmosDBName string) (*autorest.Response, *errhelp.AzureError) {
cosmosDBName string) (*autorest.Response, error) {
cosmosDBClient, err := getCosmosDBClient()
if err != nil {
return nil, errhelp.NewAzureErrorAzureError(err)
return nil, err
}

deleteFuture, err := cosmosDBClient.Delete(ctx, groupName, cosmosDBName)
if err != nil {
return nil, errhelp.NewAzureErrorAzureError(err)
return nil, err
}

ar, err := deleteFuture.Result(cosmosDBClient)
if err != nil {
return nil, errhelp.NewAzureErrorAzureError(err)
return nil, err
}
return &ar, nil
}

// ListKeys lists the read & write keys for a database account
func (*AzureCosmosDBManager) ListKeys(
ctx context.Context,
groupName string,
accountName string) (*documentdb.DatabaseAccountListKeysResult, error) {
client, err := getCosmosDBClient()
if err != nil {
return nil, err
}

result, err := client.ListKeys(ctx, groupName, accountName)
if err != nil {
return nil, err
}

return &result, nil
}
17 changes: 10 additions & 7 deletions pkg/resourcemanager/cosmosdbs/cosmosdb_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,32 @@ import (

"github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2015-04-08/documentdb"
"github.com/Azure/azure-service-operator/api/v1alpha1"
"github.com/Azure/azure-service-operator/pkg/errhelp"
"github.com/Azure/azure-service-operator/pkg/resourcemanager"
"github.com/Azure/azure-service-operator/pkg/secrets"
"github.com/Azure/go-autorest/autorest"
)

// NewAzureCosmosDBManager creates a new cosmos db client
func NewAzureCosmosDBManager() *AzureCosmosDBManager {
return &AzureCosmosDBManager{}
func NewAzureCosmosDBManager(secretClient secrets.SecretClient) *AzureCosmosDBManager {
return &AzureCosmosDBManager{secretClient}
}

// CosmosDBManager client functions
type CosmosDBManager interface {
// CreateOrUpdateCosmosDB creates a new cosmos database account
CreateOrUpdateCosmosDB(ctx context.Context, groupName string, cosmosDBName string, location string, kind v1alpha1.CosmosDBKind, dbType v1alpha1.CosmosDBDatabaseAccountOfferType, tags map[string]*string) (*documentdb.DatabaseAccount, *errhelp.AzureError)
CreateOrUpdateCosmosDB(ctx context.Context, groupName string, cosmosDBName string, location string, kind v1alpha1.CosmosDBKind, dbType v1alpha1.CosmosDBDatabaseAccountOfferType, tags map[string]*string) (*documentdb.DatabaseAccount, error)

// GetCosmosDB gets a cosmos database account
GetCosmosDB(ctx context.Context, groupName string, cosmosDBName string) (*documentdb.DatabaseAccount, *errhelp.AzureError)
GetCosmosDB(ctx context.Context, groupName string, cosmosDBName string) (*documentdb.DatabaseAccount, error)

// DeleteCosmosDB removes the cosmos database account
DeleteCosmosDB(ctx context.Context, groupName string, cosmosDBName string) (*autorest.Response, *errhelp.AzureError)
DeleteCosmosDB(ctx context.Context, groupName string, cosmosDBName string) (*autorest.Response, error)

// CheckNameExistsCosmosDB check if the account name already exists globally
CheckNameExistsCosmosDB(ctx context.Context, accountName string) (bool, *errhelp.AzureError)
CheckNameExistsCosmosDB(ctx context.Context, accountName string) (bool, error)

// ListKeys lists the read & write keys for a database account
ListKeys(ctx context.Context, groupName string, accountName string) (*documentdb.DatabaseAccountListKeysResult, error)

resourcemanager.ARMClient
}
Loading

0 comments on commit 5b9018f

Please sign in to comment.