Skip to content

Commit

Permalink
ACC Auto-Support Bundle Support
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Haigh <mhaigh@netapp.com>
  • Loading branch information
MichaelHaigh committed May 9, 2024
1 parent 1be08bc commit 7b0d02e
Show file tree
Hide file tree
Showing 13 changed files with 541 additions and 34 deletions.
1 change: 1 addition & 0 deletions astraSDK/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from . import apiresources
from . import apps
from . import asups
from . import backups
from . import buckets
from . import clouds
Expand Down
211 changes: 211 additions & 0 deletions astraSDK/asups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#!/usr/bin/env python3
"""
Copyright 2024 NetApp, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import copy
import yaml
import json

from .common import SDKCommon


class getAsups(SDKCommon):
"""This class gets all Astra Control auto-support bundles via the core/v1/asups endpoint.
This functionality is currently only supported with ACC."""

def __init__(self, quiet=True, verbose=False, output="json", config=None):
"""quiet: Will there be CLI output or just return (datastructure)
verbose: Print all of the ReST call info: URL, Method, Headers, Request Body
output: table: pretty print the data
json: (default) output in JSON
yaml: output in yaml
config: optionally provide a pre-populated common.getConfig().main() object"""
self.quiet = quiet
self.verbose = verbose
self.output = output
super().__init__(config=config)

def main(self, triggerTypeFilter=None, uploadFilter=None):
endpoint = "core/v1/asups"
url = self.base + endpoint

data = {}
params = {}

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

if ret.ok:
results = super().jsonifyResults(ret)
if triggerTypeFilter or uploadFilter:
asupsCopy = copy.deepcopy(results)
for counter, asup in enumerate(asupsCopy.get("items")):
if triggerTypeFilter and triggerTypeFilter != asup["triggerType"]:
results["items"].remove(asupsCopy["items"][counter])
elif uploadFilter and uploadFilter != asup["upload"]:
results["items"].remove(asupsCopy["items"][counter])
if self.output == "json":
dataReturn = results
elif self.output == "yaml":
dataReturn = yaml.dump(results)
elif self.output == "table":
dataReturn = self.basicTable(
[
"asupID",
"state",
"upload",
"uploadState",
"triggerType",
"dataWindowStart",
"dataWindowEnd",
],
[
"id",
"creationState",
"upload",
"uploadState",
"triggerType",
"dataWindowStart",
"dataWindowEnd",
],
results,
)
if not self.quiet:
print(json.dumps(dataReturn) if type(dataReturn) is dict else dataReturn)
return dataReturn

else:
if not self.quiet:
if ret.status_code == 500:
super().printError("Error: the core/v1/asups API is only supported on ACC.\n")
else:
super().printError(ret)
return False


class downloadAsup(SDKCommon):
"""This class downloads an Astra Control auto-support bundles via the core/v1/asups endpoint.
This functionality is currently only supported with ACC."""

def __init__(self, quiet=True, verbose=False, config=None):
"""quiet: Will there be CLI output or just return (datastructure)
verbose: Print all of the ReST call info: URL, Method, Headers, Request Body
output: table: pretty print the data
json: (default) output in JSON
yaml: output in yaml
config: optionally provide a pre-populated common.getConfig().main() object"""
self.quiet = quiet
self.verbose = verbose
super().__init__(config=config)
self.headers["accept"] = "application/gzip"
self.headers["Content-Type"] = "application/gzip"

def main(self, asupID):
endpoint = f"core/v1/asups/{asupID}"
url = self.base + endpoint

data = {}
params = {}

ret, filename = super().downloadFile(
url, data, self.headers, params, quiet=self.quiet, verbose=self.verbose
)

if ret.ok:
if not self.quiet:
print(f"'{filename}' downloaded to current directory successfully.")
return filename

else:
if not self.quiet:
if ret.status_code == 500:
super().printError("Error: the core/v1/asups API is only supported on ACC.\n")
else:
super().printError(ret)
return False


class createAsup(SDKCommon):
"""This class creates an Astra Control auto-support bundle via the core/v1/asups endpoint.
upload: should be one of "true" or "false" (str, not bool).
dataWindowStart: JSON string containing a timestamp indicating the start time of the ASUP.
Defaults to 24 hours before dataWindowEnd, must occur before dataWindowEnd, max is 7 days
before the current time.
dataWindowEnd: JSON string containing a timestamp indicating the end time of the ASUP.
Defaults to the current time of the request.
dataWindowStart and dataWindowEnd must conform to the ISO-8601 Date Time Schema.
There is no validation of this input, that instead is left to the calling method."""

def __init__(self, quiet=True, verbose=False, config=None):
"""quiet: Will there be CLI output or just return (datastructure)
verbose: Print all of the ReST call info: URL, Method, Headers, Request Body
config: optionally provide a pre-populated common.getConfig().main() object"""
self.quiet = quiet
self.verbose = verbose
super().__init__(config=config)
self.headers["accept"] = "application/astra-asup+json"
self.headers["Content-Type"] = "application/astra-asup+json"

def main(
self,
upload,
dataWindowStart=None,
dataWindowEnd=None,
):
endpoint = "core/v1/asups"
url = self.base + endpoint
params = {}
data = {
"upload": upload,
"type": "application/astra-asup",
"version": "1.0",
}
if dataWindowStart:
data["dataWindowStart"] = dataWindowStart
if dataWindowEnd:
data["dataWindowEnd"] = dataWindowEnd

ret = super().apicall(
"post",
url,
data,
self.headers,
params,
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:
if ret.status_code == 404:
super().printError("Error: the core/v1/asups API is only supported on ACC.\n")
else:
super().printError(ret)
return False
21 changes: 19 additions & 2 deletions astraSDK/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
import json
import kubernetes
import os
import requests
import shutil
import sys
import textwrap
import yaml
from tabulate import tabulate
import textwrap
import requests
from urllib3 import disable_warnings

RED = "\033[31m"
Expand Down Expand Up @@ -229,6 +230,22 @@ def apicall(self, method, url, data, headers, params, quiet=False, verbose=False
print(f"{GREEN}API HTTP Status Code: {ret.status_code}{ENDC}")
return ret

def downloadFile(self, url, data, headers, params, filetype="tgz", quiet=False, verbose=False):
"""Download a file using the requests module"""
try:
if verbose:
self.printVerbose(url, "get", headers, data, params, self.session)
filename = f"{url.split('/')[-1]}.{filetype}"
with self.session.get(url, json=data, headers=headers, params=params, stream=True) as s:
if s.ok:
with open(filename, "wb") as f:
shutil.copyfileobj(s.raw, f)
else:
filename = False
return s, filename
except requests.exceptions.RequestException as e:
raise SystemExit(e)

def jsonifyResults(self, requestsObject):
try:
results = requestsObject.json()
Expand Down
42 changes: 34 additions & 8 deletions docs/toolkit/copy/README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,52 @@
# Copy

The `copy` argument allows you to copy application resources from one app to another. This can be useful when cloning an application, as by default these resources are not currently copied.
The `copy` argument allows you to copy application resources from one app to another, or copy Astra Control resources to your local workstation.

* [Asup](#asup)
* [Hooks](#hooks)
* [Protections](#protections)

```text
$ actoolkit copy -h
usage: actoolkit copy [-h] {hooks,protections} ...
usage: actoolkit copy [-h] {asup,hooks,protections} ...
options:
-h, --help show this help message and exit
-h, --help show this help message and exit
objectType:
{hooks,protections}
hooks copy hooks (executionHooks) from one app to another
protections copy protections from one app to another
{asup,hooks,protections}
asup copy auto-support bundle to local workstation
hooks copy all hooks (executionHooks) from one app to another
protections copy all protections from one app to another
```

## Asup

The `copy asup` command allows you to copy / download an existing auto-support bundle to your local workstation. To create an auto-support bundle, please see the [create asup](../create/README.md#asup) command.

It requires a single argument, the `asupID`, which can be gathered via the [list asups](../list/README.md#asups) command. The command usage is:

```text
actoolkit copy asup <asupID>
```

Example output:

```text
$ actoolkit copy asup b1398002-f2ad-4d73-a0e4-aed33d3e05e0
'b1398002-f2ad-4d73-a0e4-aed33d3e05e0.tgz' downloaded to current directory successfully.
```

You can then view the downloaded auto-support bundle:

```text
$ ls -l b1398002*
-rw-r--r-- 1 mhaigh staff 13M May 9 10:04 b1398002-f2ad-4d73-a0e4-aed33d3e05e0.tgz
```

## Hooks

The `copy hooks` command allows you to copy all execution hooks from a source app to a destination app. The command usage is:
The `copy hooks` command allows you to copy all execution hooks from a source app to a destination app. This can be useful when cloning an application, as by default these resources are not currently copied. The command usage is:

```text
actoolkit copy hooks <sourceAppID> <destinationAppID>
Expand All @@ -36,7 +62,7 @@ $ actoolkit copy hooks 1c252557-b5d3-4446-b5fe-c41ed2b0595c 6676813f-4f6c-4487-9

## Protections

The `copy protections` command allows you to copy all protection policies from a source app to a destination app. The command usage is:
The `copy protections` command allows you to copy all protection policies from a source app to a destination app. This can be useful when cloning an application, as by default these resources are not currently copied. The command usage is:

```text
actoolkit copy protections <sourceAppID> <destinationAppID>
Expand Down

0 comments on commit 7b0d02e

Please sign in to comment.