Skip to content

Commit

Permalink
Merge pull request #983 from jpflueger/cosmosdb-geo-redundancy
Browse files Browse the repository at this point in the history
Cosmosdb geo redundancy
  • Loading branch information
Justin Pflueger authored Apr 29, 2020
2 parents 1646383 + f0f32c3 commit 80a7082
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 121 deletions.
8 changes: 4 additions & 4 deletions api/v1alpha1/cosmosdb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type CosmosDBSpec struct {
Properties CosmosDBProperties `json:"properties,omitempty"`
VirtualNetworkRules *[]CosmosDBVirtualNetworkRule `json:"virtualNetworkRules,omitempty"`
KeyVaultToStoreSecrets string `json:"keyVaultToStoreSecrets,omitempty"`
Locations *[]CosmosDBLocation `json:"locations,omitempty"`
IPRules *[]string `json:"ipRules,omitempty"`
}

Expand Down Expand Up @@ -66,13 +67,12 @@ const (
CosmosDBDatabaseAccountOfferTypeStandard CosmosDBDatabaseAccountOfferType = "Standard"
)

/*
// CosmosDBLocation defines one or more locations for geo-redundancy and high availability
type CosmosDBLocation struct {
FailoverPriority int `json:"failoverPriority,omitempty"`
LocationName string `json:"locationName,omitempty"`
LocationName string `json:"locationName"`
FailoverPriority int32 `json:"failoverPriority"`
IsZoneRedundant bool `json:"isZoneRedundant,omitempty"`
}
*/

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
Expand Down
15 changes: 12 additions & 3 deletions config/samples/azure_v1alpha1_cosmosdb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ spec:
resourceGroup: resourcegroup-azure-operators
properties:
databaseAccountOfferType: Standard
enableMultipleWriteLocations: false

# optionally turn on multi-region writes
# enableMultipleWriteLocations: true

# Optionally set the capabilities name to the following options: (the default is SQL)
# "EnableCassandra", "EnableTable", "EnableGremlin", "EnableMongo"
# NOTE: If using "EnableMongo" kind must be set to MongoDB for this to take effect
#capabilities:
# - name: "EnableCassandra"


# optionally set the mongoDBVersion to "3.2" or "3.6", if omitted the default is "3.2"
# NOTE: kind must be set to MongoDB for this to take effect
# mongoDBVersion: "3.6"
Expand All @@ -34,4 +35,12 @@ spec:
# # the ips in this rule are needed to access your db from the portal
# - 104.42.195.92,40.76.54.131,52.176.6.30,52.169.50.45,52.187.184.26
# # add additional ips you would like to grant access
# - 73.153.28.188
# - 1.2.3.4

# optionally configure multiple regions and availability zone redundancy
# locations:
# - locationName: eastus
# failoverPriority: 0
# isZoneRedundant: true
# - locationName: westus
# failoverPriority: 1
48 changes: 48 additions & 0 deletions config/samples/azure_v1alpha1_cosmosdb_prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
apiVersion: azure.microsoft.com/v1alpha1
kind: CosmosDB
metadata:
name: cosmosdb-sample-2
labels:
CosmosAccountType: Production
spec:
kind: GlobalDocumentDB
location: eastus
resourceGroup: resourcegroup-azure-operators
properties:
databaseAccountOfferType: Standard

# turn on multi-region writes for production
enableMultipleWriteLocations: true

# Optionally set the capabilities name to the following options: (the default is SQL)
# "EnableCassandra", "EnableTable", "EnableGremlin", "EnableMongo"
# NOTE: If using "EnableMongo" kind must be set to MongoDB for this to take effect
#capabilities:
# - name: "EnableCassandra"

# optionally set the mongoDBVersion to "3.2" or "3.6", if omitted the default is "3.2"
# NOTE: kind must be set to MongoDB for this to take effect
# mongoDBVersion: "3.6"

# enable virtual network rules if configured below
# isVirtualNetworkFilterEnabled: true

# optionally restrict access to specific virtual networks
# virtualNetworkRules:
# - subnetId: /subscriptions/{subscription_id}/resourceGroups/{resourcegroup}/providers/Microsoft.Network/virtualNetworks/{vnet_name}/subnets/{subnet_name}
# ignoreMissingServiceEndpoint: false

# optionally configure different CIDR IP ranges for allowed-list, omitting allows all or falls back to vNetRules
ipRules:
# the ips in this rule are needed to access your db from the portal
- 104.42.195.92,40.76.54.131,52.176.6.30,52.169.50.45,52.187.184.26
# # add additional ips you would like to grant access
# - 1.2.3.4

# configure multiple regions and availability zone redundancy
locations:
- locationName: eastus
failoverPriority: 0
isZoneRedundant: true
- locationName: westus
failoverPriority: 1
171 changes: 89 additions & 82 deletions pkg/resourcemanager/cosmosdbs/cosmosdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,106 +40,42 @@ func getCosmosDBClient() (documentdb.DatabaseAccountsClient, error) {
// CreateOrUpdateCosmosDB creates a new CosmosDB
func (*AzureCosmosDBManager) CreateOrUpdateCosmosDB(
ctx context.Context,
groupName string,
cosmosDBName string,
location string,
kind v1alpha1.CosmosDBKind,
networkRule *[]v1alpha1.CosmosDBVirtualNetworkRule,
ipRules *[]string,
properties v1alpha1.CosmosDBProperties,
tags map[string]*string) (*documentdb.DatabaseAccount, error) {
accountName string,
spec v1alpha1.CosmosDBSpec,
tags map[string]*string) (*documentdb.DatabaseAccount, string, error) {
cosmosDBClient, err := getCosmosDBClient()
if err != nil {
return nil, err
}

dbKind := documentdb.DatabaseAccountKind(kind)
sDBType := string(properties.DatabaseAccountOfferType)
bWriteLocal := bool(properties.EnableMultipleWriteLocations)
vnetEnabled := bool(properties.IsVirtualNetworkFilterEnabled)

var capabilities []documentdb.Capability
if properties.Capabilities != nil {
for _, i := range *properties.Capabilities {
name := i.Name
capabilities = append(capabilities, documentdb.Capability{
Name: name,
})
}
} else {
capabilities = make([]documentdb.Capability, 0)
}

/*
* Current state of Locations and CosmosDB properties:
* Creating a Database account with CosmosDB requires
* that DatabaseAccountCreateUpdateProperties be sent over
* and currently we are not reading most of these values in
* as part of the Spec for CosmosDB. We are currently
* specifying a single Location as part of a location array
* which matches the location set for the overall CosmosDB
* instance. This matches the general behavior of creating
* a CosmosDB instance in the portal where the only
* geo-relicated region is the sole region the CosmosDB
* is created in.
*/
locationObj := documentdb.Location{
ID: to.StringPtr(fmt.Sprintf("%s-%s", cosmosDBName, location)),
FailoverPriority: to.Int32Ptr(0),
LocationName: to.StringPtr(location),
}
locationsArray := []documentdb.Location{
locationObj,
}

vNetRulesSet := []documentdb.VirtualNetworkRule{}
if networkRule != nil {
for _, i := range *networkRule {
subnetID := i.SubnetID
ignoreEndpoint := i.IgnoreMissingVNetServiceEndpoint
vNetRulesSet = append(vNetRulesSet, documentdb.VirtualNetworkRule{
ID: subnetID,
IgnoreMissingVNetServiceEndpoint: ignoreEndpoint,
})
}
}

sIPRules := ""
if ipRules != nil {
sIPRules = strings.Join(*ipRules, ",")
return nil, "", err
}

createUpdateParams := documentdb.DatabaseAccountCreateUpdateParameters{
Location: to.StringPtr(location),
Location: &spec.Location,
Tags: tags,
Name: &cosmosDBName,
Kind: dbKind,
Type: to.StringPtr("Microsoft.DocumentDb/databaseAccounts"),
ID: &cosmosDBName,
Name: &accountName,
Kind: documentdb.DatabaseAccountKind(spec.Kind),
DatabaseAccountCreateUpdateProperties: &documentdb.DatabaseAccountCreateUpdateProperties{
DatabaseAccountOfferType: &sDBType,
IsVirtualNetworkFilterEnabled: &vnetEnabled,
VirtualNetworkRules: &vNetRulesSet,
EnableMultipleWriteLocations: &bWriteLocal,
Locations: &locationsArray,
Capabilities: &capabilities,
IPRangeFilter: &sIPRules,
DatabaseAccountOfferType: getAccountOfferType(spec),
IsVirtualNetworkFilterEnabled: &spec.Properties.IsVirtualNetworkFilterEnabled,
VirtualNetworkRules: getVirtualNetworkRules(spec),
EnableMultipleWriteLocations: &spec.Properties.EnableMultipleWriteLocations,
Locations: getLocations(spec),
Capabilities: getCapabilities(spec),
IPRangeFilter: getIPRangeFilter(spec),
},
}
createUpdateFuture, err := cosmosDBClient.CreateOrUpdate(
ctx, groupName, cosmosDBName, createUpdateParams)

ctx, spec.ResourceGroup, accountName, createUpdateParams)
if err != nil {
// initial create request failed, wrap error
return nil, err
return nil, "", err
}

result, err := createUpdateFuture.Result(cosmosDBClient)
if err != nil {
// there is no immediate result, wrap error
return &result, err
return &result, createUpdateFuture.PollingURL(), err
}
return &result, nil
return &result, createUpdateFuture.PollingURL(), nil
}

// GetCosmosDB gets the cosmos db account
Expand Down Expand Up @@ -222,3 +158,74 @@ func (*AzureCosmosDBManager) ListKeys(

return &result, nil
}

func getAccountOfferType(spec v1alpha1.CosmosDBSpec) *string {
kind := string(spec.Properties.DatabaseAccountOfferType)
if kind == "" {
kind = string(documentdb.Standard)
}
return &kind
}

func getLocations(spec v1alpha1.CosmosDBSpec) *[]documentdb.Location {
if spec.Locations == nil || len(*spec.Locations) <= 1 {
return &[]documentdb.Location{
{
LocationName: to.StringPtr(spec.Location),
FailoverPriority: to.Int32Ptr(0),
IsZoneRedundant: to.BoolPtr(false),
},
}
}

locations := make([]documentdb.Location, len(*spec.Locations))
for i, l := range *spec.Locations {
locations[i] = documentdb.Location{
LocationName: to.StringPtr(l.LocationName),
FailoverPriority: to.Int32Ptr(l.FailoverPriority),
IsZoneRedundant: to.BoolPtr(l.IsZoneRedundant),
}
}
return &locations
}

func getVirtualNetworkRules(spec v1alpha1.CosmosDBSpec) *[]documentdb.VirtualNetworkRule {
if spec.VirtualNetworkRules == nil {
return nil
}

vNetRules := make([]documentdb.VirtualNetworkRule, len(*spec.VirtualNetworkRules))
for i, r := range *spec.VirtualNetworkRules {
vNetRules[i] = documentdb.VirtualNetworkRule{
ID: r.SubnetID,
IgnoreMissingVNetServiceEndpoint: r.IgnoreMissingVNetServiceEndpoint,
}
}
return &vNetRules
}

func getCapabilities(spec v1alpha1.CosmosDBSpec) *[]documentdb.Capability {
capabilities := []documentdb.Capability{}
if spec.Kind == v1alpha1.CosmosDBKindMongoDB && spec.Properties.MongoDBVersion == "3.6" {
capabilities = []documentdb.Capability{
{Name: to.StringPtr("EnableMongo")},
}
}
if spec.Properties.Capabilities != nil {
for _, i := range *spec.Properties.Capabilities {
name := i.Name
capabilities = append(capabilities, documentdb.Capability{
Name: name,
})
}
}
return &capabilities
}

func getIPRangeFilter(spec v1alpha1.CosmosDBSpec) *string {
sIPRules := ""
if spec.IPRules != nil {
sIPRules = strings.Join(*spec.IPRules, ",")
}
return &sIPRules
}
2 changes: 1 addition & 1 deletion pkg/resourcemanager/cosmosdbs/cosmosdb_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func NewAzureCosmosDBManager(secretClient secrets.SecretClient) *AzureCosmosDBMa
// 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, networkRule *[]v1alpha1.CosmosDBVirtualNetworkRule, ipRules *[]string, properties v1alpha1.CosmosDBProperties, tags map[string]*string) (*documentdb.DatabaseAccount, error)
CreateOrUpdateCosmosDB(ctx context.Context, cosmosDBName string, spec v1alpha1.CosmosDBSpec, tags map[string]*string) (*documentdb.DatabaseAccount, string, error)

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

0 comments on commit 80a7082

Please sign in to comment.