Skip to content

Commit

Permalink
Merge pull request #1126 from jpflueger/rediscacheaction-reboot
Browse files Browse the repository at this point in the history
RedisCacheAction reboot
  • Loading branch information
Justin Pflueger authored Jun 4, 2020
2 parents df00e2a + 23ae244 commit 5da5eb0
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 29 deletions.
12 changes: 8 additions & 4 deletions api/v1alpha1/rediscacheaction_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +kubebuilder:validation:Enum=rollallkeys;rollprimarykey;rollsecondarykey
// +kubebuilder:validation:Enum=rollallkeys;rollprimarykey;rollsecondarykey;rebootallnodes;rebootprimarynode;rebootsecondarynode
type RedisCacheActionName string

const (
RedisCacheActionNameRollAllKeys RedisCacheActionName = "rollallkeys"
RedisCacheActionNameRollPrimaryKey RedisCacheActionName = "rollprimarykey"
RedisCacheActionNameRollSecondaryKey RedisCacheActionName = "rollsecondarykey"
RedisCacheActionNameRollAllKeys RedisCacheActionName = "rollallkeys"
RedisCacheActionNameRollPrimaryKey RedisCacheActionName = "rollprimarykey"
RedisCacheActionNameRollSecondaryKey RedisCacheActionName = "rollsecondarykey"
RedisCacheActionNameRebootAllNodes RedisCacheActionName = "rebootallnodes"
RedisCacheActionNameRebootPrimaryNode RedisCacheActionName = "rebootprimarynode"
RedisCacheActionNameRebootSecondaryNode RedisCacheActionName = "rebootsecondarynode"
)

// RedisCacheActionSpec defines the desired state of RedisCacheAction
Expand All @@ -23,6 +26,7 @@ type RedisCacheActionSpec struct {
ActionName RedisCacheActionName `json:"actionName"`
SecretName string `json:"secretName,omitempty"`
KeyVaultToStoreSecrets string `json:"keyVaultToStoreSecrets,omitempty"`
ShardID *int32 `json:"shardID,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
7 changes: 6 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion config/samples/azure_v1alpha1_rediscacheaction.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ metadata:
spec:
resourceGroup: resourcegroup-azure-operators
cacheName: rediscache-sample-1
# possible values are 'rollallkeys', 'rollprimarykey', 'rollsecondarykey'
# possible values are 'rollallkeys', 'rollprimarykey', 'rollsecondarykey', 'rebootallnodes', 'rebootprimarynode', 'rebootsecondarynode'
actionName: rollallkeys
19 changes: 19 additions & 0 deletions docs/services/rediscache/rediscache.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,25 @@ The `redisCache` indicates the RedisCache on which you want to configure the new

_Note:_ When the `startIP` and `endIP` are 0.0.0.0, it denotes a special case that adds a firewall rule to allow all Azure services to access the RedisCache.

## RedisCache action

The RedisCache action allows you to regenerate keys and reboot the RedisCache cluster.

Here is a [sample YAML](/config/samples/azure_v1alpha1_rediscacheaction.yaml) for RedisCache action.

The `cacheName` indicates the RedisCache on which you want to perform the action and `resourceGroup` is the resource group of the RedisCache. The `actionName` corresponds to one of the supported actions listed below.

### RedisCache action - Roll Keys
The `secretName` field is used to update the RedisCache secret. The `keyVaultToStoreSecrets` field is used to specify a KeyVault instance where the RedisCache secret exists. The following "roll" actions are supported:
- `rollprimarykey` - regenerates primary key and updates the secret
- `rollsecondarykey` - regenerates secondary key and updates the secret
- `rollallkeys` - regenerates primary and secondary keys and updates the secret

### RedisCache action - Reboot
The `shardID` field is used to specify a specific RedisCache shard to reboot. The following "reboot" actions are supported:
- `rebootprimarynode` - reboots all primary nodes in the RedisCache cluster
- `rebootsecondarynode` - reboots all secondary nodes in the RedisCache cluster
- `rebootallnodes` - reboots all nodes (primary & secondary) in the RedisCache cluster

## Deploy, view and delete resources

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type RedisCacheActionManager interface {

RegenerateSecondaryAccessKey(ctx context.Context, resourceGroup string, cacheName string) (string, error)

ForceReboot(ctx context.Context, resourceGroup string, cacheName string) error

// also embed async client methods
resourcemanager.ARMClient
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,41 +34,52 @@ func (m *AzureRedisCacheActionManager) Ensure(ctx context.Context, obj runtime.O
return true, nil
}

rollAllKeys := instance.Spec.ActionName == v1alpha1.RedisCacheActionNameRollAllKeys
if isRedisCacheRollAction(instance.Spec.ActionName) {
rollAllKeys := instance.Spec.ActionName == v1alpha1.RedisCacheActionNameRollAllKeys

if rollAllKeys || instance.Spec.ActionName == v1alpha1.RedisCacheActionNameRollPrimaryKey {
if err = m.RegeneratePrimaryAccessKey(ctx, instance.Spec.ResourceGroup, instance.Spec.CacheName); err != nil {
instance.Status.Message = err.Error()
return false, err
}
}

if rollAllKeys || instance.Spec.ActionName == v1alpha1.RedisCacheActionNameRollSecondaryKey {
if err = m.RegenerateSecondaryAccessKey(ctx, instance.Spec.ResourceGroup, instance.Spec.CacheName); err != nil {
instance.Status.Message = err.Error()
return false, err
}
}

if rollAllKeys || instance.Spec.ActionName == v1alpha1.RedisCacheActionNameRollPrimaryKey {
if err = m.RegeneratePrimaryAccessKey(ctx, instance.Spec.ResourceGroup, instance.Spec.CacheName); err != nil {
cacheInstance := &v1alpha1.RedisCache{
ObjectMeta: metav1.ObjectMeta{
Name: instance.Spec.CacheName,
Namespace: instance.Namespace,
},
Spec: v1alpha1.RedisCacheSpec{
SecretName: instance.Spec.SecretName,
ResourceGroupName: instance.Spec.ResourceGroup,
},
}
if err = m.ListKeysAndCreateSecrets(ctx, cacheInstance); err != nil {
instance.Status.Provisioning = true
instance.Status.Provisioned = false
instance.Status.FailedProvisioning = true
instance.Status.Message = err.Error()
return false, err
}
}

if rollAllKeys || instance.Spec.ActionName == v1alpha1.RedisCacheActionNameRollSecondaryKey {
if err = m.RegenerateSecondaryAccessKey(ctx, instance.Spec.ResourceGroup, instance.Spec.CacheName); err != nil {
if isRedisCacheRebootAction(instance.Spec.ActionName) {
err := m.ForceReboot(ctx, instance.Spec.ResourceGroup, instance.Spec.CacheName, instance.Spec.ActionName, instance.Spec.ShardID)
if err != nil {
instance.Status.Message = err.Error()
return false, err
}
}

// regenerate the secret
cacheInstance := &v1alpha1.RedisCache{
ObjectMeta: metav1.ObjectMeta{
Name: instance.Spec.CacheName,
Namespace: instance.Namespace,
},
Spec: v1alpha1.RedisCacheSpec{
SecretName: instance.Spec.SecretName,
ResourceGroupName: instance.Spec.ResourceGroup,
},
}
if err = m.ListKeysAndCreateSecrets(ctx, cacheInstance); err != nil {
instance.Status.Provisioned = false
instance.Status.FailedProvisioning = true
instance.Status.Message = err.Error()
return false, err
}

// successful return
instance.Status.Provisioning = true
instance.Status.Provisioned = true
instance.Status.FailedProvisioning = false
instance.Status.Message = resourcemanager.SuccessMsg
Expand Down Expand Up @@ -120,3 +131,15 @@ func (m *AzureRedisCacheActionManager) convert(obj runtime.Object) (*v1alpha1.Re
}
return local, nil
}

func isRedisCacheRollAction(actionName v1alpha1.RedisCacheActionName) bool {
return actionName == v1alpha1.RedisCacheActionNameRollAllKeys ||
actionName == v1alpha1.RedisCacheActionNameRollPrimaryKey ||
actionName == v1alpha1.RedisCacheActionNameRollSecondaryKey
}

func isRedisCacheRebootAction(actionName v1alpha1.RedisCacheActionName) bool {
return actionName == v1alpha1.RedisCacheActionNameRebootAllNodes ||
actionName == v1alpha1.RedisCacheActionNameRebootPrimaryNode ||
actionName == v1alpha1.RedisCacheActionNameRebootSecondaryNode
}
30 changes: 30 additions & 0 deletions pkg/resourcemanager/rediscaches/actions/rediscacheactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package actions

import (
"context"
"fmt"

"github.com/Azure/azure-service-operator/api/v1alpha1"
"github.com/Azure/azure-service-operator/pkg/resourcemanager/rediscaches"
"github.com/Azure/azure-service-operator/pkg/secrets"

Expand Down Expand Up @@ -62,3 +64,31 @@ func (r *AzureRedisCacheActionManager) RegenerateSecondaryAccessKey(ctx context.

return nil
}

func (r *AzureRedisCacheActionManager) ForceReboot(ctx context.Context, resourceGroup string, cacheName string, actionName v1alpha1.RedisCacheActionName, shardID *int32) error {
client, err := r.GetRedisCacheClient()
if err != nil {
return err
}

var rebootType model.RebootType
switch actionName {
case v1alpha1.RedisCacheActionNameRebootAllNodes:
rebootType = model.AllNodes
case v1alpha1.RedisCacheActionNameRebootPrimaryNode:
rebootType = model.PrimaryNode
case v1alpha1.RedisCacheActionNameRebootSecondaryNode:
rebootType = model.SecondaryNode
default:
return fmt.Errorf("%v is not a valid reboot action", actionName)
}

_, err = client.ForceReboot(ctx, resourceGroup, cacheName, model.RebootParameters{
RebootType: rebootType,
ShardID: shardID,
})
if err != nil {
return err
}
return err
}

0 comments on commit 5da5eb0

Please sign in to comment.