Skip to content

Commit

Permalink
Merge pull request #154 from sassoftware/develop
Browse files Browse the repository at this point in the history
Merge develop branch in preparation for release 1.6.0
  • Loading branch information
kevinlinglesas authored Nov 3, 2021
2 parents 299223a + 134b32f commit a25dc78
Show file tree
Hide file tree
Showing 17 changed files with 299 additions and 53 deletions.
2 changes: 2 additions & 0 deletions deployment_report/templates/viya_deployment_report.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,14 @@
<th>SAS Custom Resource</th>
</tr>
{% for discovered_type, type_details in report_data.kubernetes.discoveredResourceTypes.items() %}
{% if type_details.kind | lower != "none" %}
<tr>
<td>{{ type_details.kind }}</td>
<td>{{ discovered_type }}</td>
<td>{{ type_details.count }}</td>
<td>{{ type_details.sasCRD }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
Expand Down
35 changes: 21 additions & 14 deletions pre_install_report/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ VIYA_MIN_AGGREGATE_WORKER_CPU_CORES=56
If calculated aggregate memory is less than a percentage (85%) of VIYA_MIN_AGGREGATE_WORKER_MEMORY then the tool will flag a memory issue.
If calculated aggregate vCPUs is less than VIYA_MIN_AGGREGATE_WORKER_CPU_CORES then it the tool will flag a CPU issue.

SAS recommends using the SAS Viya 4 Infrastructure as Code (IaC) tools to create a cluster for [Microsoft Azure](https://github.com/sassoftware/viya4-iac-azure),
[AWS](https://github.com/sassoftware/viya4-iac-aws]), or [GCP](https://github.com/sassoftware/viya4-iac-gcp)

SAS recommends using the SAS Viya 4 Infrastructure as Code (IaC) tools to create a cluster.
Refer to the following IaC repositories for [Microsoft Azure](https://github.com/sassoftware/viya4-iac-azure), [AWS](https://github.com/sassoftware/viya4-iac-aws]) or [GCP](https://github.com/sassoftware/viya4-iac-gcp).
For OpenShift refer to the documentation in SAS® Viya® Operations [OpenShift](https://go.documentation.sas.com/doc/en/itopscdc/v_019/itopssr/n1ika6zxghgsoqn1mq4bck9dx695.htm#p1c8bxlbu0gzuvn1e75nck1yozcn)

**Example**: Setting for aggregate Memory and vCPU for deployment based on documentation in SAS Viya Operations under System Requirements
in the Hardware and Resource Requirements section. See Sizing Recommendations for Microsoft Azure.
Expand Down Expand Up @@ -71,12 +71,13 @@ Download the latest version of this tool and update required packages with every

## Usage

**Note:** You must set your `KUBECONFIG` environment variable. `KUBECONFIG` must have administrator rights in the
namespace where you intend to deploy your SAS Viya software.
To obtain a complete report use a `KUBECONFIG`
with administrator rights in the cluster.
**Note:** You must set your `KUBECONFIG` environment variable. `KUBECONFIG` must have administrator rights to the
cluster where you intend to deploy your SAS Viya software.
To obtain a complete report use a `KUBECONFIG` with administrator rights in the cluster. Otherwise, the report will
not be able to evaluate items such as memory, CPU cores, software versions and other node details. It is not useful
for determining if you are ready to deploy your SAS Viya software.

Create the namespace where you plan to deploy SAS Viya. You must specify the namespace when you run the tool.
Create the namespace where you plan to deploy SAS Viya. A namespace is required to run this tool. Specify the namespace where you plan to deploy SAS Viya using the namespace option. If a namespace is not provided, the tool will check the current context for a namespace. Ensure that you are running with the correct namespace.

After obtaining the latest version of this tool, cd to `<tool-download-dir>/viya4-ark`.

Expand All @@ -86,20 +87,26 @@ The following command provides usage details:
python3 viya-ark.py pre-install-report -h
```

**Note:** The tool currently expects an NGINX Ingress controller. Other Ingress controllers are not evaluated.
### Supported Ingress Values
The tool currently supports the following ingress controllers: _nginx, openshift_.
Other ingress controllers are not evaluated. Select _openshift_ if you are deploying on Red Hat OpenShift.

### Hints
**Note:** The values for the Ingress Host and Port values are not required if you specify an ingress value
of _openshift_. The Ingress Host and Port values must be specified if you specify an ingress
value of _nginx_.

The values for the Ingress Host and Ingress Port options can be determined with kubectl commands.
The following section provides hints for a NGINX Ingress controller of Type LoadBalancer.
The following commands
may need to be modified to suit your Ingress controller deployment.

You must specify the namespace where the Ingress controller is available as well as the Ingress controller name:
The following section provides hints for a _nginx_ ingress controller of Type LoadBalancer.
The following commands may need to be modified to suit your ingress controller deployment.

You must specify the namespace where the ingress controller is available as well as the ingress controller name:

```
kubectl -n <nginx-ingress-namespace> get svc <nginx-ingress-controller-name>
```


Here is sample output from the command:

Expand Down Expand Up @@ -129,7 +136,7 @@ python3 viya-ark.py pre-install-report -i nginx -H $INGRESS_HOST -p $INGRESS_HT

## Report Output

The tool generates the pre-install check report,`viya_pre_install_report_<timestamp>.html. The report is in a
The tool generates the pre-install check report, viya_pre_install_report_<timestamp>.html. The report is in a
web-viewable, HTML format.

## Modify CPU, Memory, and Version Settings
Expand Down
11 changes: 9 additions & 2 deletions pre_install_report/library/pre_install_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def __init__(self, sas_logger: ViyaARKLogger, viya_kubelet_version_min,
self._calculated_aggregate_memory = None
self._workers = 0
self._aggregate_nodeStatus_failures = 0
self._ingress_controller = None

def _parse_release_info(self, release_info):
"""
Expand All @@ -92,7 +93,7 @@ def _parse_release_info(self, release_info):

def check_details(self, kubectl, ingress_port, ingress_host, ingress_controller,
output_dir):

self._ingress_controller = ingress_controller
self._kubectl = kubectl
name_space = kubectl.get_namespace()
self.logger.info("names_space: {} ".format(name_space))
Expand Down Expand Up @@ -395,19 +396,25 @@ def _check_permissions(self, permissions_check: PreCheckPermissions):
permissions_check.manage_pvc(viya_constants.KUBECTL_APPLY, False)
permissions_check.check_sample_application()
permissions_check.check_sample_ingress()
if self._ingress_controller == viya_constants.OPENSHIFT_INGRESS:
permissions_check.check_openshift_route()
permissions_check.check_deploy_crd()
permissions_check.check_rbac_role()
permissions_check.check_create_custom_resource()
permissions_check.check_get_custom_resource(namespace)

if self._ingress_controller == viya_constants.OPENSHIFT_INGRESS:
permissions_check.get_openshift_route_details()
permissions_check.check_openshift_route_host_port()
permissions_check.check_delete_custom_resource()
permissions_check.check_rbac_delete_role()

permissions_check.check_sample_response()

permissions_check.check_delete_crd()
permissions_check.check_delete_sample_application()
permissions_check.check_delete_sample_ingress()
if self._ingress_controller == viya_constants.OPENSHIFT_INGRESS:
permissions_check.check_delete_openshift_route()
# Check the status of deployed PVCs
permissions_check.manage_pvc(viya_constants.KUBECTL_APPLY, True)
# Delete all Deployed PVCs
Expand Down
135 changes: 113 additions & 22 deletions pre_install_report/library/pre_install_check_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
INGRESS_V1BETA1_REL_EQ = '==1.18'
INGRESS_UNSUPPORTED_REL_LT = '<1.18'

OPS_ROUTE_NAME = "no-route-hello-world"
OPS_ROUTE_KEY = "host"
OPS_ROUTE_KIND = "route"


class PreCheckPermissions(object):
"""
Expand Down Expand Up @@ -84,6 +88,8 @@ def __init__(self, params):
self._sample_deployment = 0
self._sample_output = ""
self._k8s_git_version = None
self._openshift_host_port = viya_constants.NO_HOST_FOUND
self._route_k8s_resource: KubernetesResource = None

def _set_results_cluster_admin(self, resource_key, rc):
"""
Expand Down Expand Up @@ -136,8 +142,6 @@ def _set_results_namespace_admin(self, resource_key, rc, message=""):
viya_constants.INSUFFICIENT_PERMS + ". Check Logs."
else:
self.namespace_admin_permission_data[resource_key] = viya_constants.ADEQUATE_PERMS
# self.namespace_admin_permission_aggregate[viya_constants.PERM_PERMISSIONS] = \
# viya_constants.ADEQUATE_PERMS

def _get_pvc(self, pvc_name, key):
"""
Expand Down Expand Up @@ -363,7 +367,7 @@ def _set_results_namespace_admin_crd(self, resource_key, rc):

def check_sample_application(self):
"""
Deploy hello-world in specified namespace and set the permissiions status in the
Deploy hello-world in specified namespace and set the permissions status
"""

Expand Down Expand Up @@ -398,6 +402,86 @@ def check_sample_application(self):

return 1

def check_openshift_route(self):

rc = self.utils.deploy_manifest_file(viya_constants.KUBECTL_APPLY,
'hello_ops_route_no_host.yaml')

if rc == 0:
self._set_results_namespace_admin(viya_constants.PERM_DEPLOYMENT, rc)
self._set_results_namespace_admin(viya_constants.PERM_ROUTER, rc)
else:
self._sample_deployment = 1
self._set_results_namespace_admin(viya_constants.PERM_DEPLOYMENT, rc)
self._set_results_namespace_admin(viya_constants.PERM_ROUTER, rc)
return 1

def get_openshift_route_details(self):
"""
Get host/port of deployed route name
action: issue kubectl command to get host/port value in route
"""
self._route_k8s_resource: KubernetesResource = self.utils.get_resource(OPS_ROUTE_KIND, OPS_ROUTE_NAME)

if self._route_k8s_resource is not None:
self.logger.info("route json{}".format(pprint.pformat(self._route_k8s_resource.as_dict())))
else:
self.logger.info("route is {}".format(pprint.pformat(str(type(self._route_k8s_resource)))))

def check_delete_openshift_route(self):
"""
Delete hello-world Kubernetes Service in specified namespace. Set the
permissions status in the namespace_admin_permission_data dict object.
"""
rc = self.utils.deploy_manifest_file(viya_constants.KUBECTL_DELETE,
'hello_ops_route_no_host.yaml')
self._set_results_namespace_admin(viya_constants.PERM_DELETE + viya_constants.PERM_ROUTER, rc)

def set_route_k8s_resource(self, route: KubernetesResource):
"""
Set the route information as KubernetesResource
Mainly used for pytest
"""
self._route_k8s_resource: KubernetesResource = route

def get_route_host(self):
"""
Get the route host/port retrieved from route: KubernetesResource
Mainly used for pytest
"""
return str(self._openshift_host_port)

def get_ingress_controller(self):
"""
Get the current ingress_controller
"""
return str(self.ingress_controller)

def check_openshift_route_host_port(self):
"""
Get host/port of deployed route name = "no-route-hello-world"
action: issue kubectl command to get host/port value in route
"""
if self._route_k8s_resource is not None:

ingress = self._route_k8s_resource.get_status_value("ingress")

for dic in ingress:
for ingress_key, val in dic.items():
# print(f'{ingress_key} is {val}')
if ingress_key == OPS_ROUTE_KEY:
self._openshift_host_port = val
self.logger.info("host_port {}".format(pprint.pformat(self._openshift_host_port)))

if self._openshift_host_port == viya_constants.NO_HOST_FOUND:
self.logger.error("host_port {}".format(pprint.pformat(self._openshift_host_port)))

def check_sample_service(self):
"""
Deploy Kubernetes Service for hello-world appliction in specified namespace and set the
Expand Down Expand Up @@ -468,7 +552,11 @@ def check_sample_response(self):
if self.ingress_port is not None:
port = ":" + self.ingress_port
host_port_app = str(self.ingress_host) + str(port) + "/hello-world"

url_string = "http://" + host_port_app
if self.ingress_controller == viya_constants.OPENSHIFT_INGRESS:
url_string = "http://" + str(self._openshift_host_port) + "/hello-world"

self.logger.info("url {}".format(url_string))
response = self._request_url(url_string, True)
if response is not None:
Expand All @@ -478,26 +566,29 @@ def check_sample_response(self):
" " + str(response.text)
self.logger.info("url {} response status code {}".format(url_string, str(response.status_code)))
else:
# attempt the request again with https and verify=False option, suppress InsecureRequestWarning
url_string = "https://" + host_port_app
response = self._request_url(url_string, False)
if response is not None:
response.encoding = 'utf-8'
if response.status_code == 200:
self.namespace_admin_permission_data[viya_constants.PERM_SAMPLE_STATUS] = \
str(response.status_code) + " " + str(response.text)
self.logger.info("url {} response status code {}".format(url_string, str(response.status_code)))
if self.ingress_controller != viya_constants.OPENSHIFT_INGRESS:

# attempt the request again with https and verify=False option, suppress InsecureRequestWarning
url_string = "https://" + host_port_app
response = self._request_url(url_string, False)
if response is not None:
response.encoding = 'utf-8'
if response.status_code == 200:
self.namespace_admin_permission_data[viya_constants.PERM_SAMPLE_STATUS] = \
str(response.status_code) + " " + str(response.text)
self.logger.info("url {} response status code {}".format(url_string,
str(response.status_code)))
else:
self.namespace_admin_permission_aggregate[viya_constants.PERM_PERMISSIONS] = \
viya_constants.INSUFFICIENT_PERMS

self.namespace_admin_permission_data['Sample HTTP Failed'] = "Status Code " + \
str(response.status_code) + \
": " + str(url_string)
self.logger.info("url {} status {} text {}".format(url_string,
response.status_code, response.text))
else:
self.namespace_admin_permission_aggregate[viya_constants.PERM_PERMISSIONS] = \
viya_constants.INSUFFICIENT_PERMS

self.namespace_admin_permission_data['Sample HTTP Failed'] = "Status Code " + \
str(response.status_code) + \
": " + str(url_string)
self.logger.info("url {} status {} text {}".format(url_string,
response.status_code, response.text))
else:
self.logger.error("Retry as https failed url {}".format(url_string))
self.logger.error("Retry as https failed url {}".format(url_string))

def _request_url(self, url_string, verify_cert=True):
"""
Expand Down
21 changes: 21 additions & 0 deletions pre_install_report/library/utils/hello_ops_route_no_host.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
####################################################################
#### hello_ops_route_no_host.yaml ####
####################################################################
####################################################################
#### Author: SAS Institute Inc. ####
#### ####
####################################################################
####################################################################
#
# Copyright (c) 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
#
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: no-route-hello-world
spec:
to:
kind: Service
name: hello-world
3 changes: 3 additions & 0 deletions pre_install_report/library/utils/viya_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@
ADEQUATE_PERMS = "Adequate"
INGRESS_NGINX = "nginx"
INGRESS_ISTIO = "istio"
OPENSHIFT_INGRESS = "openshift"
NO_HOST_FOUND = "No_host_found"
INGRESS_CONTROLLER = "ingress_controller"
INGRESS_HOST = "ingress_host"
INGRESS_PORT = "ingress_port"
KUBECTL = "kubectl "
PERM_PERMISSIONS = "Permissions"
PERM_DEPLOYMENT = "Deployment"
PERM_SERVICE = "Service"
PERM_ROUTER = "Openshift Route"
PERM_AZ_FILE = "AzureFile Storage RWX"
PERM_AZ_FILE_PR = "AzureFilePremium Storage RWX"
PERM_AZ_DISK = "AzureDisk Storage"
Expand Down
2 changes: 1 addition & 1 deletion pre_install_report/library/utils/viya_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
'specified in the pre_install_report/viya_deployment_settings.ini file'
OPTION_ERROR = "ERROR: option {} not recognized"
OPTION_VALUES_ERROR = "ERROR: Provide valid values for all required options. Check options -i, -p and -H."
INGRESS_CONTROLLER_ERROR = "ERROR: Ingress controller specified must be nginx. Check value on option -i "
INGRESS_CONTROLLER_ERROR = "ERROR: Ingress controller specified must be nginx or openshift. Check value on option -i "
OUPUT_PATH_ERROR = "ERROR: The report output path is not valid {}. Check value on option -o "
EXCEPTION_MESSAGE = "ERROR: {}"
KUBECONF_FILE_ERROR = "ERROR: The file specified in the KUBECONFIG environment does not exist. " \
Expand Down
Loading

0 comments on commit a25dc78

Please sign in to comment.