Skip to content

Commit

Permalink
Merge pull request #102 from sassoftware/develop
Browse files Browse the repository at this point in the history
Merged develop branch to main for next release.
  • Loading branch information
kevinlinglesas authored May 12, 2021
2 parents 9225483 + 2cae847 commit 2dcac88
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 42 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SAS Viya ARK provides the following types of assistance:
* Post-deployment automation and utilities

## Prerequisites for SAS Viya ARK
Obtain the latest version of SAS Viya ARK with every new software order.
Obtain the latest version of SAS Viya ARK whenever you pull down new deployment assets or a new manifest.

Each tool that is included in the resource kit provides a readme that describes its specific prerequisites and functionality.

Expand All @@ -23,6 +23,7 @@ SAS Viya ARK tools require third-party packages be installed before use. All req
```commandline
$ python3 -m pip install -r requirements.txt
```
The Python packages are only required on the host where SAS Viya ARK tools are executed.

## Index of Tools
Tool support for the latest release of SAS Viya:
Expand Down
39 changes: 20 additions & 19 deletions deployment_report/model/viya_deployment_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,25 +521,6 @@ def get_sas_component_resources(self, component_name: Text, resource_kind: Text)
except KeyError:
return None

def get_cadence_version(self, resource: KubernetesResource) -> Optional[Text]:
"""
Returns the combined key values from the 'data' dictionary.
:param key: The key of the value to return.
:return: The value mapped to the given key, or None if the given key doesn't exist.
"""
cadence_info: Optional[Text] = None
try:
if 'sas-deployment-metadata' in resource.get_name():
cadence_data = resource.get_data()
cadence_info = cadence_data['SAS_CADENCE_NAME'].capitalize() + ' ' + \
cadence_data['SAS_CADENCE_VERSION'] + ' (' + \
cadence_data['SAS_CADENCE_RELEASE'] + ')'

return cadence_info
except KeyError:
return None

def write_report(self, output_directory: Text = OUTPUT_DIRECTORY_DEFAULT,
data_file_only: bool = DATA_FILE_ONLY_DEFAULT,
include_resource_definitions: bool = INCLUDE_RESOURCE_DEFINITIONS_DEFAULT,
Expand Down Expand Up @@ -584,3 +565,23 @@ def write_report(self, output_directory: Text = OUTPUT_DIRECTORY_DEFAULT,
include_definitions=include_resource_definitions)

return os.path.abspath(data_file_path), html_file_path

@staticmethod
def get_cadence_version(resource: KubernetesResource) -> Optional[Text]:
"""
Returns the cadence version of the targeted SAS deployment.
:param resource: The key of the value to return.
:return: A string representing the cadence version of the targeted SAS deployment.
"""
cadence_info: Optional[Text] = None
try:
if 'sas-deployment-metadata' in resource.get_name():
cadence_data: Optional[Dict] = resource.get_data()
cadence_info = \
(f"{cadence_data['SAS_CADENCE_NAME'].capitalize()} {cadence_data['SAS_CADENCE_VERSION']} "
f"({cadence_data['SAS_CADENCE_RELEASE']})")

return cadence_info
except KeyError:
return None
29 changes: 19 additions & 10 deletions download_pod_logs/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,28 +216,37 @@ def _write_log(kubectl: KubectlInterface, pod: KubernetesResource, tail: int, ou
output_file.writelines(("#" * 50) + "\n\n")

# call kubectl to get the log for this container

log: List[AnyStr] = list()
try:
log = kubectl.logs(pod_name=pod.get_name(), container_name=container_status.get_name(),
prefix=False, tail=tail, ignore_errors=False)
except CalledProcessError as e:
prefix=False, tail=tail)
except CalledProcessError as container_err:
# container log has error, we'll retrieve log from initContainers
# add log from previous container call
log += [e.output.decode("utf-8")]
initcontainers: Optional[List[Dict]]
initcontainers = pod.get_spec_value(KubernetesResource.Keys.INIT_CONTAINERS)

# add anything returned in the raised error
if container_err.stdout:
log += str(container_err.stdout.decode()).splitlines()

if container_err.stderr:
log += str(container_err.stderr.decode()).splitlines()

initcontainers: Optional[List[Dict]] = pod.get_spec_value(KubernetesResource.Keys.INIT_CONTAINERS)
if initcontainers:
for initcontainer in initcontainers:
container_name: Optional[Text] = initcontainer.get("name")
log += ["\n" + "#" * 50] + [f"# Log from initContainer: {container_name}"] + ["#" * 50]
try:
log += kubectl.logs(pod_name=pod.get_name(),
container_name=container_name, ignore_errors=True, prefix=False,
tail=tail)
log += kubectl.logs(pod_name=pod.get_name(), container_name=container_name,
prefix=False, tail=tail)
except CalledProcessError as initcontainer_err:
# add anything returned in the raised error
if initcontainer_err.stdout:
log += str(initcontainer_err.stdout.decode()).splitlines()

if initcontainer_err.stderr:
log += str(initcontainer_err.stderr.decode()).splitlines()

except CalledProcessError:
err_msg = (f"ERROR: A log could not be retrieved for the container "
f"[{container_status.get_name()}] "
f"in pod [{pod.get_name()}] in namespace [{kubectl.get_namespace()}]")
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
jinja2>=2.11.3
Pint==0.11
requests==2.22.0
pyyaml==5.1.2
pyyaml>=5.4
ldap3==2.9
33 changes: 24 additions & 9 deletions viya_ark_library/k8s/sas_kubectl.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
####################################################################
import json

from subprocess import CalledProcessError, check_output, STDOUT
from subprocess import CalledProcessError, Popen, PIPE
from typing import AnyStr, Dict, List, Text, Union, Optional

from viya_ark_library.k8s.sas_k8s_errors import NamespaceNotFoundError
Expand Down Expand Up @@ -119,16 +119,31 @@ def __init__(self, executable: Text = "kubectl", namespace: Text = None, global_
def get_namespace(self) -> Text:
return self.namespace

def do(self, command: Text, ignore_errors: bool = False) -> AnyStr:
# try to execute the command #
try:
return check_output(f"{self.exec} {command}", shell=True, stderr=STDOUT)
except CalledProcessError as e:
# raise the error if errors are not being ignored, otherwise print the error to stdout #
def do(self, command: Text, ignore_errors: bool = False, success_rcs: Optional[List[int]] = None) \
-> AnyStr:
# set default return code list if one was not provided
if success_rcs is None:
success_rcs = [0]

# define the process to run
proc: Popen = Popen(f"{self.exec} {command}", shell=True, stdout=PIPE, stderr=PIPE)

# execute the procedure
stdout, stderr = proc.communicate()

# get the return code
rc: int = proc.returncode

# check if an acceptable code was returned
if rc not in success_rcs:
if not ignore_errors:
raise e
raise CalledProcessError(returncode=rc, cmd=f"{self.exec} {command}", output=stdout, stderr=stderr)
else:
print(f"WARNING: Error encountered executing: {self.exec} {command} "
f"(rc: {rc} | stdout: {stdout} | stderr: {stderr})")

return e.output
# return the stdout
return stdout

def api_resources(self, ignore_errors: bool = False) -> KubernetesApiResources:
# get the api-resources and convert the response into a list #
Expand Down
4 changes: 3 additions & 1 deletion viya_ark_library/k8s/sas_kubectl_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ def get_namespace(self) -> Text:
pass

@abstractmethod
def do(self, command: Text, ignore_errors: bool = False) -> AnyStr:
def do(self, command: Text, ignore_errors: bool = False, success_rcs: Optional[List[int]] = None) -> AnyStr:
"""
Generic method for executing a kubectl command.
:param command: The kubectl command to execute.
:param ignore_errors: True if errors encountered during execution should be ignored (a message will be printed
to stdout), otherwise False.
:param success_rcs: A list of return codes representing a successful execution of the command. If a None value
is provided, the default list "[0]" will be used.
:raises CalledProcessError: If the command returns a non-zero return code.
:return: The stdout of the command that was executed.
"""
Expand Down
2 changes: 1 addition & 1 deletion viya_ark_library/k8s/test_impl/sas_kubectl_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def __init__(self,
def get_namespace(self) -> Text:
return self.namespace

def do(self, command: Text, ignore_errors: bool = False) -> AnyStr:
def do(self, command: Text, ignore_errors: bool = False, success_rcs: Optional[List[int]] = None) -> AnyStr:
return "Not functional in testing implementation"

def api_resources(self, ignore_errors: bool = False) -> KubernetesApiResources:
Expand Down

0 comments on commit 2dcac88

Please sign in to comment.