Skip to content

Commit

Permalink
adding "update protection"
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Haigh <mhaigh@netapp.com>
  • Loading branch information
MichaelHaigh committed Apr 26, 2024
1 parent 2ee44eb commit b654a59
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 15 deletions.
73 changes: 73 additions & 0 deletions astraSDK/protections.py
Expand Up @@ -180,6 +180,7 @@ def main(
minute,
appID,
recurrenceRule=None,
bucketID=None,
):
endpoint = f"k8s/v1/apps/{appID}/schedules"
url = self.base + endpoint
Expand All @@ -200,6 +201,8 @@ def main(
if recurrenceRule:
data["recurrenceRule"] = recurrenceRule
data["replicate"] = "true"
if bucketID:
data["bucketID"] = bucketID

ret = super().apicall(
"post",
Expand All @@ -223,6 +226,76 @@ def main(
return False


class updateProtectionpolicy(SDKCommon):
"""Update a protection policy. This class does no validation of the arguments, leaving
that to the API call itself. tkSrc/update.py can be used as a guide as to what the API
requirements are in case the swagger isn't sufficient.
"""

def __init__(self, quiet=True, verbose=False):
"""quiet: Will there be CLI output or just return (datastructure)
verbose: Print all of the ReST call info: URL, Method, Headers, Request Body"""
self.quiet = quiet
self.verbose = verbose
super().__init__()
self.headers["Content-Type"] = "application/astra-schedule+json"

def main(
self,
appID,
protectionID,
granularity,
backupRetention,
snapshotRetention,
minute=None,
hour=None,
dayOfWeek=None,
dayOfMonth=None,
bucketID=None,
):
endpoint = f"k8s/v1/apps/{appID}/schedules/{protectionID}"
url = self.base + endpoint
params = {}
data = {
"type": "application/astra-schedule",
"version": "1.3",
"granularity": granularity,
"backupRetention": backupRetention,
"snapshotRetention": snapshotRetention,
}
if minute:
data["minute"] = minute
if hour:
data["hour"] = hour
if dayOfWeek:
data["dayOfWeek"] = dayOfWeek
if dayOfMonth:
data["dayOfMonth"] = dayOfMonth
if bucketID:
data["bucketID"] = bucketID

ret = super().apicall(
"put",
url,
data,
self.headers,
params,
self.verifySSL,
quiet=self.quiet,
verbose=self.verbose,
)

if ret.ok:
results = super().jsonifyResults(ret)
if not self.quiet:
print(json.dumps(results))
return results
else:
if not self.quiet:
super().printError(ret)
return False


class destroyProtectiontionpolicy(SDKCommon):
"""This class destroys a protection policy"""

Expand Down
55 changes: 52 additions & 3 deletions docs/toolkit/update/README.md
Expand Up @@ -5,21 +5,24 @@ The `update` argument allows you to update an Astra resource, at this time only
* [Bucket](#bucket)
* [Cloud](#cloud)
* [Cluster](#cluster)
* [Protection](#protection)
* [Replication](#replication)
* [Script](#script)

```text
$ actoolkit update -h
usage: actoolkit update [-h] {bucket,cloud,cluster,replication,script} ...
usage: actoolkit update [-h] {bucket,appVault,cloud,cluster,protection,schedule,replication,script} ...
options:
-h, --help show this help message and exit
objectType:
{bucket,cloud,cluster,replication,script}
bucket update bucket
{bucket,appVault,cloud,cluster,protection,schedule,replication,script}
bucket (appVault) update bucket
cloud update cloud
cluster update cluster
protection (schedule)
update protection policy
replication update replication
script update script
```
Expand Down Expand Up @@ -147,6 +150,52 @@ $ actoolkit update cluster d0e0767b-1d77-478d-8640-13272efe1e23 --defaultBucketI
{"type": "application/astra-managedCluster", "version": "1.6", "id": "d0e0767b-1d77-478d-8640-13272efe1e23", "name": "uscentral1", "state": "running", "stateUnready": [], "managedState": "managed", "protectionState": "full", "protectionStateDetails": [], "restoreTargetSupported": "true", "snapshotSupported": "true", "managedStateUnready": [], "managedTimestamp": "2023-11-28T14:30:42Z", "inUse": "true", "clusterType": "gke", "clusterVersion": "1.27", "clusterVersionString": "v1.27.3-gke.100", "connectorCapabilities": ["relayV1", "watcherV1", "neptuneV1"], "namespaces": [], "defaultStorageClass": "274562c4-9fff-4051-b16b-9db6db60651b", "cloudID": "d1c502e6-d410-46fc-8c15-f67c5b63dea2", "credentialID": "dcf1c466-d0fe-4bdf-b3ba-6e0e6e0ae066", "isMultizonal": "false", "tridentManagedStateAllowed": ["unmanaged"], "tridentVersion": "23.10.0-test.6d2477dfad063cd2277395663d5b06d198365c9e+6d2477dfad063cd2277395663d5b06d198365c9e", "acpVersion": "23.10.0-test.6d2477dfad063cd2277395663d5b06d198365c9e+3670363ff598b0105b8b2735323d3c0ae3ccabb8", "privateRouteID": "b68aa04d-a787-483f-9d9e-7c2930981534", "apiServiceID": "727422d9-abca-45d6-876e-3a6c62ef5664", "defaultBucketID": "", "metadata": {"labels": [{"name": "astra.netapp.io/labels/read-only/cloudName", "value": "private"}], "creationTimestamp": "2023-11-28T14:30:42Z", "modificationTimestamp": "2023-11-28T15:41:36Z", "createdBy": "45347ae2-6a07-41b0-a544-674ac4317b87"}}
```

## Protection

The `update protection` command allows you to update a [protection policy](../create/README.md#protection). The high level command usage is:

```text
actoolkit update protection <protectionID> <updateArgs>
```

The \<protectionID\> argument can be gathered from a [list protections](../list/README.md#protections) command. The available \<updateArgs\> values are (multiple can be specified with the same command):

* `-u`/`--bucketID`: modify the bucket where the backups and snapshots are storagegrid
* `-b`/`--backupRetention`: modify the number of backups to retain
* `-s`/`--snapshotRetention`: modify the number of snapshots to retain
* `-M`/`--dayOfMonth`: modify the day of the month for the policy (only valid for monthly granularity)
* `-W`/`--dayOfWeek`: modify the day of the week for the policy (only valid for weekly granularity)
* `-H`/`--hour`: modify the hour of the policy (valid for all granularities except hourly)
* `-m`/`--minute`: modify the minute of the policy (valid for all granularities)

To update the bucket, run the following command:

```text
$ actoolkit update protection 113a3140-e95d-42c9-be74-8cd169a65ae4 -u cdd3910c-6e37-4b91-beb2-57c6ed7dc7f3
{"type": "application/astra-schedule", "version": "1.3", "id": "113a3140-e95d-42c9-be74-8cd169a65ae4", "granularity": "hourly", "minute": "5", "snapshotRetention": "1", "backupRetention": "1", "bucketID": "cdd3910c-6e37-4b91-beb2-57c6ed7dc7f3"}
```

To modify the number of backups retained:

```text
$ actoolkit update protection 8cfbd961-04b9-4f7f-a094-0542aaee8626 -b 3
{"type": "application/astra-schedule", "version": "1.3", "id": "8cfbd961-04b9-4f7f-a094-0542aaee8626", "granularity": "daily", "minute": "0", "hour": "2", "snapshotRetention": "1", "backupRetention": "3", "bucketID": "5f34da97-6195-4568-af77-52e01f9ae4bf"}
```

To modify the minute the policy is executed on:

```text
$ actoolkit update protection 6967981a-cfe7-4b00-b38c-640f33223a48 -m 5
{"type": "application/astra-schedule", "version": "1.3", "id": "6967981a-cfe7-4b00-b38c-640f33223a48", "granularity": "weekly", "minute": "5", "hour": "2", "dayOfWeek": "0", "snapshotRetention": "1", "backupRetention": "1", "bucketID": "5f34da97-6195-4568-af77-52e01f9ae4bf"}
```

To modify the snapshot retention, hour, and minute of a policy:

```text
$ actoolkit update protection a3f3d02a-6c22-4d62-9436-f678d271fdc5 -m 9 -H 6 -s 3
{"type": "application/astra-schedule", "version": "1.3", "id": "a3f3d02a-6c22-4d62-9436-f678d271fdc5", "granularity": "monthly", "minute": "9", "hour": "6", "dayOfMonth": "2", "snapshotRetention": "3", "backupRetention": "1", "bucketID": "5f34da97-6195-4568-af77-52e01f9ae4bf"}
```

## Replication

The `update replication` command allows you to **failover**, **reverse**, or **resync** an existing [replication policy](../create/README.md#replication). It is currently **only** supported for ACC environments. The high level command usage is:
Expand Down
10 changes: 9 additions & 1 deletion tkSrc/choices.py
Expand Up @@ -191,6 +191,9 @@ def main(argv, verbs, verbPosition, ard, acl, v3, v3_skip_tls_verify=False):
config_context=v3, skip_tls_verify=v3_skip_tls_verify
).main("appvaults")
acl.buckets = ard.buildList("buckets", "metadata.name")
else:
ard.buckets = astraSDK.buckets.getBuckets().main()
acl.buckets = ard.buildList("buckets", "id")
if argv[verbPosition + 1] == "replication":
ard.destClusters = astraSDK.clusters.getClusters().main(hideUnmanaged=True)
acl.destClusters = ard.buildList("destClusters", "id")
Expand Down Expand Up @@ -470,7 +473,7 @@ def main(argv, verbs, verbPosition, ard, acl, v3, v3_skip_tls_verify=False):
acl.clouds = ard.buildList("clouds", "id")

elif verbs["update"] and len(argv) - verbPosition >= 2:
if argv[verbPosition + 1] == "bucket":
if argv[verbPosition + 1] == "bucket" or argv[verbPosition + 1] == "appVault":
ard.buckets = astraSDK.buckets.getBuckets().main()
acl.buckets = ard.buildList("buckets", "id")
ard.credentials = astraSDK.credentials.getCredentials().main()
Expand Down Expand Up @@ -513,6 +516,11 @@ def main(argv, verbs, verbPosition, ard, acl, v3, v3_skip_tls_verify=False):
acl.clusters = ard.buildList("clusters", "id", fKey="managedState", fVal="managed")
else:
acl.clusters = ard.buildList("clusters", "id")
elif argv[verbPosition + 1] == "protection":
ard.protections = astraSDK.protections.getProtectionpolicies().main()
acl.protections = ard.buildList("protections", "id")
ard.buckets = astraSDK.buckets.getBuckets().main()
acl.buckets = ard.buildList("buckets", "id")
elif argv[verbPosition + 1] == "replication":
ard.replications = astraSDK.replications.getReplicationpolicies().main()
if not ard.replications: # Gracefully handle ACS env
Expand Down
9 changes: 9 additions & 0 deletions tkSrc/create.py
Expand Up @@ -588,6 +588,14 @@ def main(args, parser, ard):
parser.error("'monthly' granularity requires -M / --dayOfMonth")
args.dayOfWeek = naStr
if args.v3:
if ard.needsattr("buckets"):
ard.buckets = astraSDK.k8s.getResources(
config_context=args.v3, skip_tls_verify=args.skip_tls_verify
).main("appvaults")
if args.bucket is None:
args.bucket = ard.getSingleDict("buckets", "status.state", "available", parser)[
"metadata"
]["name"]
createV3Protection(
args.v3,
args.dry_run,
Expand Down Expand Up @@ -616,6 +624,7 @@ def main(args, parser, ard):
str(args.hour),
str(args.minute),
args.app,
bucketID=args.bucket,
)
if rc is False:
raise SystemExit("astraSDK.protections.createProtectionpolicy() failed")
Expand Down
73 changes: 62 additions & 11 deletions tkSrc/parser.py
Expand Up @@ -446,6 +446,7 @@ def sub_update_commands(self):
"""update 'X'"""
self.subparserUpdateBucket = self.subparserUpdate.add_parser(
"bucket",
aliases=["appVault"],
help="update bucket",
)
self.subparserUpdateCloud = self.subparserUpdate.add_parser(
Expand All @@ -456,6 +457,11 @@ def sub_update_commands(self):
"cluster",
help="update cluster",
)
self.subparserUpdateProtection = self.subparserUpdate.add_parser(
"protection",
aliases=["schedule"],
help="update protection policy",
)
self.subparserUpdateReplication = self.subparserUpdate.add_parser(
"replication",
help="update replication",
Expand Down Expand Up @@ -1366,16 +1372,14 @@ def create_protection_args(self):
choices=(None if self.plaidMode else self.acl.apps),
help="the application to create protection schedule for",
)
if self.v3:
self.subparserCreateProtection.add_argument(
"-u",
"--appVault",
dest="bucket",
default=None,
required=True,
choices=(None if self.plaidMode else self.acl.buckets),
help="Name of the AppVault to use as the target of the backup/snapshot",
)
self.subparserCreateProtection.add_argument(
"-u",
"--appVault" if self.v3 else "--bucket",
dest="bucket",
default=None,
choices=(None if self.plaidMode else self.acl.buckets),
help="Name of the AppVault to use as the target of the backup/snapshot",
)
self.subparserCreateProtection.add_argument(
"-g",
"--granularity",
Expand Down Expand Up @@ -2020,6 +2024,52 @@ def update_cluster_args(self):
help="the new default bucket / appVault for the cluster",
)

def update_protection_args(self):
"""update protection args and flags"""
self.subparserUpdateProtection.add_argument(
"protection",
choices=(None if self.plaidMode else self.acl.protections),
help="protection to update",
)
self.subparserUpdateProtection.add_argument(
"-u",
"--bucketID",
dest="bucket",
default=None,
choices=(None if self.plaidMode else self.acl.buckets),
help="the bucket to use as the target of the backup/snapshot",
)
self.subparserUpdateProtection.add_argument(
"-b",
"--backupRetention",
type=int,
choices=range(60),
help="Number of backups to retain",
)
self.subparserUpdateProtection.add_argument(
"-s",
"--snapshotRetention",
type=int,
choices=range(60),
help="Number of snapshots to retain",
)
self.subparserUpdateProtection.add_argument(
"-M", "--dayOfMonth", type=int, choices=range(1, 32), help="Day of the month"
)
self.subparserUpdateProtection.add_argument(
"-W",
"--dayOfWeek",
type=int,
choices=range(7),
help="0 = Sunday ... 6 = Saturday",
)
self.subparserUpdateProtection.add_argument(
"-H", "--hour", type=int, choices=range(24), help="Hour in military time"
)
self.subparserUpdateProtection.add_argument(
"-m", "--minute", default=0, type=int, choices=range(60), help="Minute"
)

def update_replication_args(self):
"""update replication args and flags"""
self.subparserUpdateReplication.add_argument(
Expand Down Expand Up @@ -2137,8 +2187,9 @@ def main(self):

self.update_bucket_args()
self.update_cloud_args()
self.update_cluster_args()
self.update_protection_args()
self.update_replication_args()
self.update_script_args()
self.update_cluster_args()

return self.parser
33 changes: 33 additions & 0 deletions tkSrc/update.py
Expand Up @@ -123,6 +123,39 @@ def main(args, parser, ard):
)
if rc is False:
raise SystemExit("astraSDK.clusters.updateCluster() failed")
elif args.objectType == "protection" or args.objectType == "schedule":
if ard.needsattr("protections"):
ard.protections = astraSDK.protections.getProtectionpolicies().main()
protection = ard.getSingleDict("protections", "id", args.protection, parser)
granularity = protection["granularity"]
if granularity == "hourly" and args.hour:
parser.error(f"{granularity} granularity must not specify -H / --hour")
if granularity == "hourly" or granularity == "daily" or granularity == "monthly":
if args.dayOfWeek:
parser.error(f"{granularity} granularity must not specify -W / --dayOfWeek")
if granularity == "hourly" or granularity == "daily" or granularity == "weekly":
if args.dayOfMonth:
parser.error(f"{granularity} granularity must not specify -M / --dayOfMonth")
rc = astraSDK.protections.updateProtectionpolicy(
quiet=args.quiet, verbose=args.verbose
).main(
protection["appID"],
protection["id"],
protection["granularity"],
str(args.backupRetention) if args.backupRetention else protection["backupRetention"],
(
str(args.snapshotRetention)
if args.snapshotRetention
else protection["snapshotRetention"]
),
minute=str(args.minute) if args.minute else protection.get("minute"),
hour=str(args.hour) if args.hour else protection.get("hour"),
dayOfWeek=str(args.dayOfWeek) if args.dayOfWeek else protection.get("dayOfWeek"),
dayOfMonth=str(args.dayOfMonth) if args.dayOfMonth else protection.get("dayOfMonth"),
bucketID=args.bucket if args.bucket else protection.get("bucketID"),
)
if rc is False:
raise SystemExit("astraSDK.protection.updateProtectionpolicy() failed")
elif args.objectType == "replication":
# Gather replication data
if ard.needsattr("replications"):
Expand Down

0 comments on commit b654a59

Please sign in to comment.