From f986fd22a23526a13b72fe24b5bf3de78f8f7ed8 Mon Sep 17 00:00:00 2001 From: Satish Pandey Date: Mon, 29 Apr 2019 11:54:03 -0400 Subject: [PATCH 01/17] Readme and sample updates Change-Id: Id9c90b8bd51259925c233b4912cad9434ff5f13b --- playbooks/ldap-validator/.gitkeep | 0 playbooks/ldap-validator/Readme.md | 62 ++++ playbooks/ldap-validator/ansible.cfg | 8 + .../ldap-validator/ldaphelper.inventory.ini | 2 + .../ldap-validator/sitedefault_sample_ad.yml | 15 + .../sitedefault_sample_openldap.yml | 33 ++ .../ldap-validator/viyaldapvalidator.yml | 302 ++++++++++++++++++ 7 files changed, 422 insertions(+) create mode 100644 playbooks/ldap-validator/.gitkeep create mode 100644 playbooks/ldap-validator/Readme.md create mode 100644 playbooks/ldap-validator/ansible.cfg create mode 100644 playbooks/ldap-validator/ldaphelper.inventory.ini create mode 100644 playbooks/ldap-validator/sitedefault_sample_ad.yml create mode 100644 playbooks/ldap-validator/sitedefault_sample_openldap.yml create mode 100644 playbooks/ldap-validator/viyaldapvalidator.yml diff --git a/playbooks/ldap-validator/.gitkeep b/playbooks/ldap-validator/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/playbooks/ldap-validator/Readme.md b/playbooks/ldap-validator/Readme.md new file mode 100644 index 0000000..add9334 --- /dev/null +++ b/playbooks/ldap-validator/Readme.md @@ -0,0 +1,62 @@ +# Viya LDAP Validator + +## Purpose + +The purpose of this playbook is to validate the accuracy of some of the ldap properties provided in a sitedefault.yml file. +Running this playbook will try to connect the ldap server and fetch some of the attributes of Users and Groups. + +**Important** The tests performed here are necessary but not exhaustive. i.e., you need to at least pass all the tests in this playbook, but that is still not a full garantee of success, as the playbook is not yet able to check every single parameter for accuracy. + +## Input: + +* Inventory file + * A sample inventory file called `ldaphelper.inventory.ini` is provided with the playbook + * If you already know which server will host the Viya Core Services, update the provided inventory accordingly, so that this server is the one running the Viya LDAP Validator tests + * If the future Viya server is not yet available, you can use the default inventory as-is, in which case the tests will be executed from the Ansible Controller itself. +* Sitedefault file + * Two sample sitedefault files are included: + * `sitedefault_sample_ad.yml` and `sitedefault_sample_openldap.yml` + * You are supposed to provide your own customized sitedefault file. You can do so in 2 ways: + * By updating the line ` sitedefault_loc: ./sitedefault_sample.yml` in the `viyaldapvalidator.yml` playbook + * At the prompt, with an ansible override: `ansible-playbook viyaldapvalidator.yml -e 'sitedefault_loc=./sitedefault.yml'` + +## How to execute it + +1. Place yourself in the same directory as the playbook: + + ```bash + cd ~ + git clone https://github.com/sassoftware/viya-ark.git + cd viya-ark/playbooks/ldap-validator/ + ``` + +2. Update the Inventory and `sitedefault_loc` variable, as mentionned above + +3. Execute the playbook: + + ```bash + cd viya-ark/playbooks/ldap-validator/ + ansible-playbook viyaldapvalidator.yml + ``` + +## Checks executed + +The Viya LDAP Validator Playbook will try to validate access to your LDAP in the following ways: + +* try to connect to the Ldap server using provided hostname and port +* fetch users[5 users] attributes +* fetch group[5 users] attributes +* fetch the attributes of admin user provided in the `sitedefault.yml` file. + +## Success Criteria + +If all tasks come back OK (green), it means that all the tests passed. If any test fails, an error message should indicate the reason for the failure. + +## Future improvements + +This is a list of future checks that should be added to this playbook: +* verify that all provided field overrides exist in target ldap +* confirm that SSSD or similar has been configured and that there are matching users +* support passing certificates for the connection to LDAP + + diff --git a/playbooks/ldap-validator/ansible.cfg b/playbooks/ldap-validator/ansible.cfg new file mode 100644 index 0000000..863edd9 --- /dev/null +++ b/playbooks/ldap-validator/ansible.cfg @@ -0,0 +1,8 @@ +[defaults] +log_path = ./ldaphelper.log +inventory = ./ldaphelper.inventory.ini +host_key_checking = true +forks = 10 +retry_files_enabled = False +gathering = smart +remote_tmp = /tmp/.$USER.ansible/ diff --git a/playbooks/ldap-validator/ldaphelper.inventory.ini b/playbooks/ldap-validator/ldaphelper.inventory.ini new file mode 100644 index 0000000..49d36ec --- /dev/null +++ b/playbooks/ldap-validator/ldaphelper.inventory.ini @@ -0,0 +1,2 @@ +[CoreServices] +myhost ansible_connection=local diff --git a/playbooks/ldap-validator/sitedefault_sample_ad.yml b/playbooks/ldap-validator/sitedefault_sample_ad.yml new file mode 100644 index 0000000..b2319ed --- /dev/null +++ b/playbooks/ldap-validator/sitedefault_sample_ad.yml @@ -0,0 +1,15 @@ +config: + application: + sas.identities.providers.ldap.connection: + host: 'ad_host' + password: 'your_password' + port: '389' + url: 'ldap://${sas.identities.providers.ldap.connection.host}:${sas.identities.providers.ldap.connection.port}'' + userDN: 'CN=MY_Account,OU=Shared Accounts,OU=Users,DC=Customer,DC=com' + sas.identities.providers.ldap.group: + baseDN: 'OU=Groups,DC=Customer,DC=com' + sas.identities.providers.ldap.user: + baseDN: 'DC=Customer,DC=com' + searchFilter: 'sAMAccountName={0}' + identities: + administrator: 'your_user_id' diff --git a/playbooks/ldap-validator/sitedefault_sample_openldap.yml b/playbooks/ldap-validator/sitedefault_sample_openldap.yml new file mode 100644 index 0000000..7eab7c7 --- /dev/null +++ b/playbooks/ldap-validator/sitedefault_sample_openldap.yml @@ -0,0 +1,33 @@ +## this is a sample of what the sitedefault could look like for OpenLDAP +config: + application: + sas.identities.providers.ldap.connection: + host: 'your_ldap_hostname' + port: '389' + url: 'ldap://${sas.identities.providers.ldap.connection.host}:${sas.identities.providers.ldap.connection.port}' + anonymousBind: 'false' + userDN: 'CN=[test] SAS Demo Account,OU=Generic Accounts,OU=Admin,DC=na,DC=customer,DC=com' + password: 'dummypass' + sas.identities.providers.ldap.group: + accountId: 'name' + baseDN: 'OU=Groups,DC=na,DC=customer,DC=com' + createdDate: 'createTimestamp' + distinguishedName: 'none' + member: 'member' + modifiedDate: 'modifyTimestamp' + objectClass: 'groupOfNames' + objectFilter: '(objectClass=groupOfNames)' + searchFilter: 'dn={0}' + sas.identities.providers.ldap.user: + accountId: 'uid' + baseDN: 'dc=customer,dc=com' + createdDate: 'createTimestamp' + distinguishedName: 'none' + memberOf: 'memberOf' + modifiedDate: 'modifyTimestamp' + objectClass: 'inetOrgPerson' + objectFilter: '(objectClass=inetOrgPerson)' + searchFilter: 'uid={0}' + sas.identities: + administrator: 'your_user_id' + \ No newline at end of file diff --git a/playbooks/ldap-validator/viyaldapvalidator.yml b/playbooks/ldap-validator/viyaldapvalidator.yml new file mode 100644 index 0000000..02c58f1 --- /dev/null +++ b/playbooks/ldap-validator/viyaldapvalidator.yml @@ -0,0 +1,302 @@ +--- + +## -done- can we access LDAP? +## -done- do we get the number of users and groups we expect +## -todo- are all the fields valid? +## -todo- do these LDAP users exist locally too? +## -todo- should we configure SSSD if they don't? +## -todo- make sure the users have home directories etc... + +- hosts: CoreServices + + vars: + sitedefault_loc: ./sitedefault_sample.yml + sizelimit: 5 + # From the LDAPSEARCH doc: + # -z sizelimit + # retrieve at most sizelimit entries for a search. A sizelimit of 0 (zero) or + # none means no limit. A sizelimit of max means the maximum integer allowable + # by the protocol. A server may impose a maximal sizelimit which only the root + # user may override. + + tasks: + + - name: Include the variables from the given file, into a variable called sitedefault + include_vars: + file: "{{ sitedefault_loc }}" + name: sitedefault + tags: + - sitedefault_include + + - name: show the variables values + debug: var=sitedefault + tags: + - extradebug + + - name: Assert that the most important variables are defined + assert: + that: + - "{{ item }} is defined" + - "{{ item }} | trim != '' " + msg: | + This item is not defined or empty in your sitedefault file: + {{item}} + Please add it + with_items: + - sitedefault.config.application['sas.identities.providers.ldap.connection']['host'] + - sitedefault.config.application['sas.identities.providers.ldap.connection']['port'] + - sitedefault.config.application['sas.identities.providers.ldap.connection']['url'] + - sitedefault.config.application['sas.identities.providers.ldap.connection']['anonymousBind'] + - sitedefault.config.application['sas.identities.providers.ldap.connection']['userDN'] + - sitedefault.config.application['sas.identities.providers.ldap.connection']['password'] + - sitedefault.config.application['sas.identities.providers.ldap.user']['baseDN'] + - sitedefault.config.application['sas.identities.providers.ldap.group']['baseDN'] + - sitedefault.config.application['sas.identities']['administrator'] + tags: + - assertdefinitions + + - name: Make simpler variables + set_fact: + ldap_server_host: "{{sitedefault.config.application['sas.identities.providers.ldap.connection']['host']}}" + ldap_server_port: "{{ sitedefault.config.application['sas.identities.providers.ldap.connection']['port']}} " + ldap_protocol: "{{sitedefault.config.application['sas.identities.providers.ldap.connection']['url'].split(':')[0]}}" + ldap_anon_bind: "{{sitedefault.config.application['sas.identities.providers.ldap.connection']['anonymousBind']}}" + ldap_bind_userdn: "{{sitedefault.config.application['sas.identities.providers.ldap.connection']['userDN']}}" + ldap_bind_pw: "{{sitedefault.config.application['sas.identities.providers.ldap.connection']['password']}}" + ldap_user_basedn: "{{sitedefault.config.application['sas.identities.providers.ldap.user']['baseDN']}}" + ldap_group_basedn: "{{sitedefault.config.application['sas.identities.providers.ldap.group']['baseDN']}}" + ldap_defaultadmin_user: "{{sitedefault.config.application['sas.identities']['administrator']}}" + tags: + - makevars + +# - name: Define Variable (when default admin is provided) +# set_fact: +# ldap_defaultadmin_user: "{{sitedefault.config.application['sas.identities']['administrator']}}" +# when: sitedefault.config.application['sas.identities']['administrator'] is defined + + - name: Assert that the port is a positive integer + assert: + that: + - ldap_server_port | int > 0 + msg: | + You provided the ldap host ({{ldap_server_host}}) and port ({{ldap_server_port}}) + That does not seem right + Please review your sitedefault file + tags: + - assertport + + - name: Assert that the variable for anonymousBind is either true or false + assert: + that: + - ldap_anon_bind | bool == True or ldap_anon_bind | bool == False + msg: | + Your value for anonymousBind is '{{ldap_anon_bind}}' + It should be either 'true' or 'false' + Please review your sitedefault file + tags: + - assertbind + + + # - debug: msg="{{ldap_server_host}},{{ldap_server_port}},{{ldap_protocol}},{{ldap_anon_bind}},{{ldap_bind_userdn}},{{ldap_bind_pw}},{{ldap_user_basedn}},{{ldap_group_basedn}} " + + - name: Make sure LDAP host and port are reachable + wait_for: + host: "{{ldap_server_host}}" + port: "{{ldap_server_port | trim}}" + timeout: 1 + msg: + - We tried to reach host "{{ldap_server_host}}" on port "{{ldap_server_port}}" + - We did not get a response. + - Please ensure that the values are correct + - If they are, there may be a firewall blocking the traffic + register: ping_ldap_host + ignore_errors: no + tags: + - reachable + + # - debug: var=ping_ldap_host + + - name: "Ensure ldapsearch is available" + become: yes + become_user: root + yum: + name: ['openldap-clients'] + state: present + tags: + - packages + + - name: create the ldap search string + set_fact: + # ldapsearchstring_wider: > + # ldapsearch + # -h "{{ldap_server_host}}" + # -p "{{ldap_server_port }}" + # -D "{{ldap_bind_userdn}}" + # -w "{{ldap_bind_pw}}" + # -b "{{sitedefault.config.application['sas.identities.providers.ldap.group']['baseDN']" '(&(objectCategory=person)(objectClass=user))' + # -z 5 + # -t mail + # -LLL + # ldapsearchstring_bind: > + # ldapsearch + # -v + # -x + # -h "{{ldap_server_host}}" + # -p "{{ldap_server_port | trim}}" {% if ldap_anon_bind | bool == true %}{% elif ldap_anon_bind | bool == false %} -D "{{ldap_bind_userdn}}" -w "{{ldap_bind_pw}}" {% else %} {% endif %} + ldapsearchstring_bind: ldapsearch -v -x -h "{{ldap_server_host}}" -p "{{ldap_server_port | trim}}" {% if ldap_anon_bind | bool == true %}{% elif ldap_anon_bind | bool == false %} -D "{{ldap_bind_userdn}}" -w "{{ldap_bind_pw}}" {% else %} {% endif %} + tags: + - createsearchstring + + - name: Display the LDAP Search String + debug: var=ldapsearchstring_bind + tags: + - debug + + +## basic connection + + - name: "Do an ldapsearch with the parameters provided" + #shell: "{{ldapsearchstring_bind}} -b '' -z 5 " + shell: "{{ldapsearchstring_bind}} -z {{sizelimit}} " + ignore_errors: yes + failed_when: ldapsearch_result.rc != 0 and ldapsearch_result.rc != 4 + changed_when: false + check_mode: no + register: ldapsearch_result + tags: + - ldapsearch1 + + - name: Display the result of the LDAP search + debug: var=ldapsearch_result + tags: + - debug + + - name: Assert that the connection to LDAP worked + assert: + that: + - ldapsearch_result.rc == 0 or ldapsearch_result.rc == 4 + msg: | + Your ldapsearch query failed. The return code was {{ldapsearch_result.rc}} + Please review the error message below for more information + {{ldapsearch_result.stderr_lines}} + tags: + - assert_ldapsearch1 + + +## check group BaseDN + - name: "Do an ldapsearch for the group BaseDN" + shell: "{{ldapsearchstring_bind}} -b '{{ldap_group_basedn}}' -z {{sizelimit}} " + ignore_errors: yes + failed_when: ldapsearch_group.rc != 0 and ldapsearch_group.rc != 4 + changed_when: false + check_mode: no + register: ldapsearch_group + tags: + - group_basedn + + - name: Display the result of the LDAP search for the groups + debug: var=ldapsearch_group + tags: + - debug + + - name: Assert that ldapsearch for the group BaseDN worked + assert: + that: + - ldapsearch_group.rc == 0 or ldapsearch_group.rc == 4 + msg: | + Your ldapsearch query to search for the groups failed. Please check the group BaseDN if its correct. The return code was {{ldapsearch_group.rc}} + Please review the error message below for more information + {{ldapsearch_group.stderr_lines}} + tags: + - assert_group_basedn + +## check user BaseDN + - name: "Do an ldapsearch for the users BaseDN" + shell: "{{ldapsearchstring_bind}} -b '{{ldap_user_basedn}}' -z {{sizelimit}} " + ignore_errors: yes + failed_when: ldapsearch_user.rc != 0 and ldapsearch_user.rc != 4 + changed_when: false + check_mode: no + register: ldapsearch_user + tags: + - ldapsearch_user + + - name: Display the result of the LDAP search for the Users + debug: var=ldapsearch_user + tags: + - debug + + - name: Assert that ldapsearch for the users BaseDN worked + assert: + that: + - ldapsearch_user.rc == 0 or ldapsearch_user.rc == 4 + msg: | + Your ldapsearch query to search for the users failed.Please check the User BaseDN if its correct. The return code was {{ldapsearch_user.rc}} + Please review the error message below for more information + {{ldapsearch_user.stderr_lines}} + tags: + - assert_ldapsearch_user + + - name: "Do an ldapsearch for the Default Admin user" + shell: "{{ldapsearchstring_bind}} -b '{{ldap_user_basedn}}' '(&(objectClass=*)(sAMAccountName={{ldap_defaultadmin_user}}))'" + ignore_errors: yes + failed_when: ldapsearch_defaultadmin.rc != 0 and ldapsearch_defaultadmin.rc != 4 + changed_when: false + check_mode: no + register: ldapsearch_defaultadmin + when: ldap_defaultadmin_user is defined + tags: + - ldapsearch_defaultadmin + + - name: Display the result of the ldapsearch for the Default Admin user + debug: var=ldapsearch_defaultadmin + tags: + - debug + + + - name: data manipulations for Users Fetch + set_fact: + num_entries_user: "{{ldapsearch_user.stdout_lines | select('match', '.*numEntries:.+') | list }}" + tags: + - display + + - name: data manipulations for Group Fetch + set_fact: + num_entries_group: "{{ldapsearch_group.stdout_lines | select('match', '.*numEntries:.+') | list }}" + tags: + - display + + - name: data manipulations Default Admin User Fetch + set_fact: + num_entries_defaultadmin_user: "{{ldapsearch_defaultadmin.stdout_lines | select('match', '.*numEntries:.+') | list }}" + tags: + - display + + + + - name: "Display statistics for group BaseDN" + debug: + msg: + - "The queries returned entries" + - "{{ num_entries_group }}" + - "{{ ldapsearch_group.stdout_lines | select('match', '.*(sAMAccountName|member|memberOf|displayName|group):.+' ) | list }}" + tags: + - display + + - name: "Display statistics for User BaseDN" + debug: + msg: + - "The queries returned entries" + - "{{ num_entries_user }}" + - "{{ ldapsearch_user.stdout_lines | select('match', '.*(sAMAccountName|displayName|mail|co|title|organizationalPerson|otherMailbox):.+' ) | list }}" + tags: + - display + + - name: "Display statistics for Default Admin User" + debug: + msg: + - "The queries returned entries" + - "{{ num_entries_defaultadmin_user }}" + - "{{ ldapsearch_defaultadmin.stdout_lines | select('match', '.*(sAMAccountName|displayName|mail|co|title|organizationalPerson|otherMailbox):.+' ) | list }}" + tags: + - display From 5370523c00606e2984d4c2095aa30e196e60f9b7 Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Mon, 29 Apr 2019 12:14:44 -0400 Subject: [PATCH 02/17] Update CHANGELOG.md - Add DEPENB-876 to change log for upcoming release. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c2e7d..3058fb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Documentation updates. Bug fixes. - Issues addressed: - DEPENB-1686 - Unclear the master branch of Viya-ARK is associated with SAS Viya 3.4 + - DEPENB-876 - LDAP validator From ee62a4c90e5053d8d979e5a42c5a52153d3e31e2 Mon Sep 17 00:00:00 2001 From: Josh Woods Date: Mon, 29 Apr 2019 12:15:12 -0400 Subject: [PATCH 03/17] (DEPENB-1689) Issue encountered with non-numeric package sizes and report not created when error hit gathering data --- playbooks/deployment-report/README.md | 10 +-- .../library/get_sas_host_details.py | 24 +++++++- .../library/process_sas_host_details.py | 61 ++++++++++++++++--- .../templates/viya_deployment_report.html.j2 | 56 +++++++++++++++++ 4 files changed, 134 insertions(+), 17 deletions(-) diff --git a/playbooks/deployment-report/README.md b/playbooks/deployment-report/README.md index 2df9c9a..518dd61 100644 --- a/playbooks/deployment-report/README.md +++ b/playbooks/deployment-report/README.md @@ -29,7 +29,7 @@ The output files written to the `sas_viya_playbook/` are: ## Running the Playbook To run the playbook, execute the following command: ```bash - ansible-playbook viya-deployment-report.yml -i + ansible-playbook viya-ark/playbooks/deployment-report/viya-deployment-report.yml ``` > **Note**: `inventory_file` should be replaced by the path to the inventory file used when deploying the SAS Viya software. @@ -37,21 +37,21 @@ To run the playbook, execute the following command: To create a report which contains a listing of files installed by each package: ```bash - ansible-playbook viya-deployment-report.yml -i -e "include_package_files=true" + ansible-playbook viya-ark/playbooks/deployment-report/viya-deployment-report.yml -e "include_package_files=true" ``` > **Note**: including this option will greatly increase the size of the report and report data. To create a report using existing data: ```bash - ansible-playbook viya-deployment-report.yml -i -e "existing_data_file=" + ansible-playbook viya-ark/playbooks/deployment-report/viya-deployment-report.yml -e "existing_data_file=" ``` To exclude the static web-page and only create the report data: ```bash - ansible-playbook viya-deployment-report.yml -i -e "exclude_html=true" + ansible-playbook viya-ark/playbooks/deployment-report/viya-deployment-report.yml -e "exclude_html=true" ``` To force the creation of the report files into the current directory: ```bash - ansible-playbook viya-deployment-report.yml -i -e 'output_dir=./' + ansible-playbook viya-ark/playbooks/deployment-report/viya-deployment-report.yml -e 'output_dir=./' ``` diff --git a/playbooks/deployment-report/library/get_sas_host_details.py b/playbooks/deployment-report/library/get_sas_host_details.py index 8c74474..1c8f2d6 100644 --- a/playbooks/deployment-report/library/get_sas_host_details.py +++ b/playbooks/deployment-report/library/get_sas_host_details.py @@ -175,6 +175,7 @@ class _HostDetailsKeys(object): :cvar str SAS_PACKAGES: Key referencing *sas_packages* (dict) in *sas_host_details* (dict). :cvar str SAS_SERVICES: Key referencing *sas_services* (dict) in *sas_host_details* (dict). :cvar str UNREACHABLE: Key referencing *_unreachable* (bool) in *sas_host_details* (dict). + :cvar str FAILED: Key referencing *_failed* (bool) in *sas_host_details* (dict) """ ID = '_id' IPV4 = 'ipv4' @@ -186,6 +187,7 @@ class _HostDetailsKeys(object): SAS_PACKAGES = 'sas_packages' SAS_SERVICES = 'sas_services' UNREACHABLE = '_unreachable' + FAILED = '_failed' # ===== # Class: OSKeys(object) @@ -927,6 +929,11 @@ def main(): # if this script is executing then the host is reachable host_details[_HostDetailsKeys.UNREACHABLE] = False + # set if host encountered failure + # if this script is executing, a failure scenario is unlikely but the value is set to True + # and only reset once all data gathering is done + host_details[_HostDetailsKeys.FAILED] = True + # set ipv4 host_details[_HostDetailsKeys.IPV4] = ipv4 @@ -971,6 +978,9 @@ def main(): services[service_name][_HostDetailsKeys.SASServicesKeys.InstalledServiceKeys.INSTALLED_BY] = \ package_name + # data gathering is done, set failed state to False + host_details[_HostDetailsKeys.FAILED] = False + results = { hostname: host_details } @@ -1518,6 +1528,9 @@ def _get_sas_package_update_info_yum(module): # -- package update info -- # # run package info command + # by default, _execute_command check for a return code of 0 for success + # if packages are found with available updates, the command will return 100 + # so 100 is provided as an additional success scenario (0 or 100) info_cmd_stdout = _execute_command("yum -q check-updates 'sas-*'", module, 100) # split stdout into an array by line, containing update info per package on each line @@ -1567,7 +1580,10 @@ def _get_sas_package_update_info_zypper(module): # -- package update info -- # # run package info command - info_cmd_stdout = _execute_command("zypper -n list-updates | grep 'sas-'", module) + # by default, _execute_command check for a return code of 0 for success + # if packages are not found with available updates, the grep command will return 1 + # so 1 is provided as an additional success scenario (0 or 1) + info_cmd_stdout = _execute_command("zypper -n list-updates | grep 'sas-'", module, 1) # split stdout into an array by line, containing update info per package on each line all_update_info = info_cmd_stdout.split("\n") @@ -1675,7 +1691,11 @@ def _bytesHumanReadable(num_bytes, unit_step=1024.0): :rtype str: """ - num_bytes = float(num_bytes) + try: + num_bytes = float(num_bytes) + except ValueError: + return "" + unit = 'bytes' if (num_bytes / unit_step) >= 1: diff --git a/playbooks/deployment-report/library/process_sas_host_details.py b/playbooks/deployment-report/library/process_sas_host_details.py index 7570da7..147bce4 100644 --- a/playbooks/deployment-report/library/process_sas_host_details.py +++ b/playbooks/deployment-report/library/process_sas_host_details.py @@ -86,19 +86,58 @@ def main(): results['created'] = report_timestamp for inventory_hostname, host_vars in hostvars.items(): - if host_vars.get(registered_dict_name) is not None: - results['sas_hosts'].update(host_vars.get(registered_dict_name)['results']) - else: + + # set up returnable values + unreachable = True + failed = True + failure_details = dict( + msg="", + rc=0, + stderr="", + stdout="", + ) + + # get the host details dict + host_details = host_vars.get(registered_dict_name) + + # check if the host has the registered dict + if host_details is not None: + + # host details exist, so host was reachable + unreachable = False + + # check if the host failed + failed = host_details['failed'] + + # if the module reported a failure, collect details + if failed: + failure_details['msg'] = host_details['msg'] + failure_details['rc'] = host_details['rc'] + failure_details['stderr'] = host_details['module_stderr'] + failure_details['stdout'] = host_details['module_stdout'] + else: + # get module results + host_results = host_details.get('results') + + if host_results is not None: + results['sas_hosts'].update(host_results) + else: + failed = True + + # if the results dict could not be found, mark the host as unreachable + if failed or unreachable: host_groups = host_vars.get('group_names') if host_groups is not None and 'sas-all' in host_groups: - hostname = host_vars.get('ansible_host') - if hostname is None: + hostname = host_vars.get('ansible_fqdn') + if hostname is None or hostname == "": hostname = host_vars.get('ansible_hostname') - if hostname is None: - hostname = host_vars.get('inventory_hostname') - if hostname is None: - hostname = inventory_hostname + if hostname is None or hostname == "": + hostname = host_vars.get('ansible_host') + if hostname is None or hostname == "": + hostname = host_vars.get('inventory_hostname') + if hostname is None or hostname == "": + hostname = inventory_hostname try: host_groups.remove('sas-all') @@ -107,7 +146,9 @@ def main(): results['sas_hosts'][hostname] = dict( _id=hostname.replace('.', '-'), - _unreachable=True, + _unreachable=unreachable, + _failed=failed, + _failure_details=failure_details, ansible_host_groups=host_groups ) else: diff --git a/playbooks/deployment-report/templates/viya_deployment_report.html.j2 b/playbooks/deployment-report/templates/viya_deployment_report.html.j2 index ff4ab1f..4abf31e 100644 --- a/playbooks/deployment-report/templates/viya_deployment_report.html.j2 +++ b/playbooks/deployment-report/templates/viya_deployment_report.html.j2 @@ -219,6 +219,15 @@ ul.column-list { .ui-accordion-header.package-update-available { background: #C0E3F6; } + +div.error-output-display { + padding: 20px; + background-color: #202020; + color: red; + margin-bottom: 15px; + font-family: "Courier New", Courier, monospace; + border-radius: 5px; +} @@ -252,6 +261,53 @@ ul.column-list {

{{ host[0] }} (UNREACHABLE!)

+ +
+ +

Inventory Host Groups

+
    +{% for host_group in host[1].ansible_host_groups | sort %} +
  • {{ host_group }}
  • +{% endfor %} +
+
+
+{% elif host[1]._failed %} +

{{ host[0] }} (FAILURE!)

+
+ +

Failure Details

+ + +
+

A failure occurred while gathering machine details. Review the output below and the + Ansible log for more information.

+
+ + +
+
Message
+
+ {{ host[1]._failure_details.msg }} (return code: {{ host[1]._failure_details.rc }}) +
+
+ + +
+
stdout
+
+ {{ host[1]._failure_details.stdout }} +
+
+ + +
+
stderr
+
+ {{ host[1]._failure_details.stderr }} +
+
+
From 5478904a85c1484d729f2d296f1652584c6c5e0d Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Mon, 29 Apr 2019 12:19:48 -0400 Subject: [PATCH 04/17] Update CHANGELOG.md Add DEPENB-1689 to change log for upcoming release. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3058fb5..cf8cade 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Issues addressed: - DEPENB-1686 - Unclear the master branch of Viya-ARK is associated with SAS Viya 3.4 - DEPENB-876 - LDAP validator + - DEPENB-1689 - Fix for no report when error hit gathering data. From cb9528130abddd6a88939ad34cdb502cf8415b04 Mon Sep 17 00:00:00 2001 From: Sherrell Crenshaw Date: Wed, 1 May 2019 09:48:43 -0400 Subject: [PATCH 05/17] Depenb 1635 Incorporate VI specific prereqs --- playbooks/pre-install-playbook/README.md | 2 -- .../viya-ark.preinstall/defaults/main.yml | 23 +++++++++++-- .../tasks/pre.required_packages_config.yml | 34 +++++++++++++++++-- .../tasks/pre.semaphores_config.yml | 1 + 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/playbooks/pre-install-playbook/README.md b/playbooks/pre-install-playbook/README.md index 91f1961..7fadc86 100644 --- a/playbooks/pre-install-playbook/README.md +++ b/playbooks/pre-install-playbook/README.md @@ -7,8 +7,6 @@ Use this playbook to prepare for a deployment of SAS Viya 3.4. This playbook does not require you to provide the details of your software Order. It will therefore apply all usual pre-reqs for Visual Analytics, Visual Statistics, and Visual Data Mining and Machine Learning, on all machines, regardless of their role. -At this time, the playbook will only perform some of the pre-requisites for Visual Investigator. Work is under-way to finalize this. - ## Prerequisites for Running the Pre-installation Playbook Before running this playbook, take the following steps: diff --git a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/defaults/main.yml b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/defaults/main.yml index 16d645c..1601274 100644 --- a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/defaults/main.yml +++ b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/defaults/main.yml @@ -39,7 +39,7 @@ storage_list: min_mem_mb: 80000 ## Minimum number of cores on each machine -min_cores_num: 4 +min_cores_num: 8 ## command used to count the cores: # commenting out because this does not work well on OpenStack # "cat /proc/cpuinfo | grep 'cpu cores' | uniq | awk -F'[:]' '{print $2}' " @@ -92,6 +92,22 @@ ulimits: use_max: true use_min: false value: 100000 + - + comment: "Added (4) for SAS Viya VI Installation" + domain: "{{sas_user}}" + item: nofile + type: "-" + use_max: true + use_min: false + value: 150000 + - + comment: "Added (5) for SAS Viya VI Installation" + domain: "{{sas_user}}" + item: nproc + type: "-" + use_max: true + use_min: false + value: 100000 # max_hostname_length: 64 ## official number from the doc @@ -176,15 +192,16 @@ required_python_min_version: "2.6" DefaultTimeoutStopSec: 1800s DefaultTimeoutStartSec: 1800s - semaphores: - { name: kernel.sem , value: 512 32000 256 1024 } - { name: net.core.somaxconn, value: 2048 } - { name: vm.max_map_count, value: 262144 } - + - { name: vm.overcommit_memory, value: 0 } ## added for VI swappiness: 1 +jq_url: "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64" + ## do a 60 seconds pause at the begginning if not using the --check option use_pause: true diff --git a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml index 4aef4ef..a8d50ab 100644 --- a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml +++ b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml @@ -5,8 +5,8 @@ # Test harness: # make it pass # ansible-playbook viya_pre_install_playbook.yml -i inventory --tags required_packages_config -e use_pause=0 -# make it fail -# +# make it fail for jq by using a bad url +# ansible-playbook viya_pre_install_playbook.yml -i pre-install.inventory.ini --tags required_packages_config -e use_pause=0 -e jq_url=https://www.abcxyz.com/foo - block: ## block start @@ -130,6 +130,36 @@ - systemd - packages + ## Install jq-1.5 utility for VI + - block: + + - name: "Download jq-1.5 utility" + get_url: + url: "{{jq_url}}" + dest: "{{playbook_dir}}/jq" + mode: a+x + + - name: "Check for downloaded content, {{playbook_dir}}/jq file" + stat: + path: "{{playbook_dir}}/jq" + register: jq_util_file + + - name: "Copy jq utility to /usr/bin" + copy: + src: "{{playbook_dir}}/jq" + dest: /usr/bin/jq + mode: a+x + when: jq_util_file.stat.exists + + - name: "Delete pre-copied jq utility from {{playbook_dir}}/jq" + file: + path: "{{playbook_dir}}/jq" + state: absent + + tags: + - jq + - packages + ## block end tags: - required_packages_config diff --git a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.semaphores_config.yml b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.semaphores_config.yml index c8d345b..ae2a6e6 100644 --- a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.semaphores_config.yml +++ b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.semaphores_config.yml @@ -8,6 +8,7 @@ value: "{{item.value}}" state: present sysctl_set: yes + reload: yes with_items: - "{{semaphores}}" tags: From b41594a637eaf0b4ab6642f715ba9aa84a963805 Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Wed, 1 May 2019 09:51:48 -0400 Subject: [PATCH 06/17] Update CHANGELOG.md Add DEPENB-1635 to changelog for upcoming release. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf8cade..00dde73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - DEPENB-1686 - Unclear the master branch of Viya-ARK is associated with SAS Viya 3.4 - DEPENB-876 - LDAP validator - DEPENB-1689 - Fix for no report when error hit gathering data. + - DEPENB-1635 - Incorporate VI specific prereqs From 302a143f9da139074d23e962190dfb59148019d7 Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Wed, 1 May 2019 12:20:00 -0400 Subject: [PATCH 07/17] Update CHANGELOG.md Added Ansible Support section to changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00dde73..88dd347 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - DEPENB-876 - LDAP validator - DEPENB-1689 - Fix for no report when error hit gathering data. - DEPENB-1635 - Incorporate VI specific prereqs +- Ansible Support: Ansible 2.4 - Ansible 2.7 From aaeeb17cf3e5bcdb1cf7684268937f36c5c34a35 Mon Sep 17 00:00:00 2001 From: Josh Woods Date: Wed, 1 May 2019 13:14:17 -0400 Subject: [PATCH 08/17] (DEPENB-1713): Deployment Report: java_memory and h_read_memory uninitialized if service is down --- playbooks/deployment-report/library/get_sas_host_details.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/playbooks/deployment-report/library/get_sas_host_details.py b/playbooks/deployment-report/library/get_sas_host_details.py index 1c8f2d6..a182a1a 100644 --- a/playbooks/deployment-report/library/get_sas_host_details.py +++ b/playbooks/deployment-report/library/get_sas_host_details.py @@ -1256,6 +1256,7 @@ def _get_sas_service_info(module): if status == _ServiceStatus.UP: java_memory = _get_process_memory_info(pid, module) else: + java_memory = dict() java_memory['RESIDENT_MEMORY'] = "Service not running" java_memory['VIRTUAL_MEMORY'] = '-' java_memory['JAVA_HEAP'] = '-' @@ -1265,6 +1266,10 @@ def _get_sas_service_info(module): print("java_memory[RESIDENT_MEMORY] = %s" % java_memory['RESIDENT_MEMORY']) h_read_memory = _bytesHumanReadable(java_memory['RESIDENT_MEMORY']) total_memory += java_memory['RESIDENT_MEMORY'] + else: + # no need to do anything with total_memory, it's defaulted to 0 and we couldn't + # find a valid value to add + h_read_memory = "-" service_attributes = { _HostDetailsKeys.SASServicesKeys.InstalledServiceKeys.ServiceAttributesKeys.STATUS: status, From 198c1517119ee85c250832f821d0386857fd4458 Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Wed, 1 May 2019 13:17:17 -0400 Subject: [PATCH 09/17] Update CHANGELOG.md Add DEPENB-1713 to changelog for upcoming release. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88dd347..8f749cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - DEPENB-876 - LDAP validator - DEPENB-1689 - Fix for no report when error hit gathering data. - DEPENB-1635 - Incorporate VI specific prereqs + - DEPENB-1713 - Deployment Report: memory uninitialized if service down. - Ansible Support: Ansible 2.4 - Ansible 2.7 From 98de8dc82d38a9c3ad9cd55a00f3d96693a9783c Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Wed, 1 May 2019 13:19:29 -0400 Subject: [PATCH 10/17] Update CHANGELOG.md Summarizing release content. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f749cd..2dcf801 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ## Viya34-ark-1.2 - May 1, 2019 - **Summary**: - Documentation updates. Bug fixes. + LDAP validtor tool. VI support. Documentation updates. Bug fixes. - Issues addressed: - DEPENB-1686 - Unclear the master branch of Viya-ARK is associated with SAS Viya 3.4 - DEPENB-876 - LDAP validator From 451881cd1a08ea7bb33094286b6c1a844b808c6d Mon Sep 17 00:00:00 2001 From: Kevin Lingle Date: Wed, 1 May 2019 13:21:10 -0400 Subject: [PATCH 11/17] Clarification & typo :/ --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dcf801..38f8d3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ## Viya34-ark-1.2 - May 1, 2019 - **Summary**: - LDAP validtor tool. VI support. Documentation updates. Bug fixes. + LDAP validator tool. VI pre-install playbook support. Documentation updates. Bug fixes. - Issues addressed: - DEPENB-1686 - Unclear the master branch of Viya-ARK is associated with SAS Viya 3.4 - DEPENB-876 - LDAP validator From 1d89c8c43a5e5e20db939866a9b370ceebb18dbb Mon Sep 17 00:00:00 2001 From: Erwan Granger <32554862+erwangranger@users.noreply.github.com> Date: Fri, 3 May 2019 10:01:05 -0400 Subject: [PATCH 12/17] Fixing an issue with the code that deploys jq The previous method was failing as the playbook folder only existed on the Ansible Controller. Also, with the new code, jq is only installed when it's missing. --- .../tasks/pre.required_packages_config.yml | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml index a8d50ab..fe7c145 100644 --- a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml +++ b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml @@ -133,28 +133,36 @@ ## Install jq-1.5 utility for VI - block: - - name: "Download jq-1.5 utility" - get_url: - url: "{{jq_url}}" - dest: "{{playbook_dir}}/jq" - mode: a+x - - - name: "Check for downloaded content, {{playbook_dir}}/jq file" - stat: - path: "{{playbook_dir}}/jq" - register: jq_util_file - - - name: "Copy jq utility to /usr/bin" - copy: - src: "{{playbook_dir}}/jq" - dest: /usr/bin/jq - mode: a+x - when: jq_util_file.stat.exists - - - name: "Delete pre-copied jq utility from {{playbook_dir}}/jq" - file: - path: "{{playbook_dir}}/jq" - state: absent + - name: Determine if jq is available + changed_when: false + check_mode: no + ignore_errors: yes + shell: which jq + register: which_jq + + # - debug: var=which_jq + ## Block start (if jq can't be found) + + - block: + - name: Confirm that /usr/bin/jq does not exist + stat: + path: "/usr/bin/jq" + register: usr_bin_jq + + - name: Display whether /usr/bin/jq exists or not + debug: var=usr_bin_jq + + - name: "If jq is not found in /usr/bin, download jq-1.5 utility into it" + get_url: + url: "{{jq_url}}" + dest: "/usr/bin/jq" + mode: 0755 + owner: root + group: root + when: usr_bin_jq.stat.exists == false + + ## block end (if jq can't be found) + when: which_jq.rc != 0 tags: - jq From d43bedba1095792bf604de12cfed6cb9118e8ae5 Mon Sep 17 00:00:00 2001 From: kevinlinglesas <36995745+kevinlinglesas@users.noreply.github.com> Date: Mon, 6 May 2019 12:53:43 -0400 Subject: [PATCH 13/17] Add jq delpoy fix to CHANGELOG --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f8d3e..58d0338 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog for SAS Viya-ARK +# Viya34-ark-1.3 - May 6, 2019 + +- **Summary**: + Bug fixes. +- Issues addressed: + - DEPENB-1716 - Fix jq installation issues on remote hosts +- Ansible Support: Ansible 2.4 - Ansible 2.7 + + + ## Viya34-ark-1.2 - May 1, 2019 - **Summary**: @@ -13,8 +23,6 @@ - DEPENB-1713 - Deployment Report: memory uninitialized if service down. - Ansible Support: Ansible 2.4 - Ansible 2.7 - - ## Viya34-ark-1.1 - April 18, 2019 - **Summary**: From 05d879739755088064953c55025bbe7a0bc580fc Mon Sep 17 00:00:00 2001 From: kevinlinglesas <36995745+kevinlinglesas@users.noreply.github.com> Date: Tue, 13 Aug 2019 18:25:56 -0400 Subject: [PATCH 14/17] DEPENB-2009 Workaround for systemd package update to latest. Task will no longer run. This is a temporary workaround for issues found with systemd 219-67 (the current 'latest') version of systemd. The task has been commented out of the playbook for now while the issue is investigated further. --- .../tasks/pre.required_packages_config.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml index d20e2d7..8584deb 100644 --- a/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml +++ b/playbooks/pre-install-playbook/roles/viya-ark.preinstall/tasks/pre.required_packages_config.yml @@ -65,13 +65,13 @@ ## we need systemd to be above 219-30 ## try to make sure we have the latest one. ## - - name: Ensures systemd package is the most recent - package: - name: systemd - state: latest - when: ansible_distribution == redhat_os_name|string and ansible_distribution_major_version == '7' - tags: - - packages + #- name: Ensures systemd package is the most recent + # package: + # name: systemd + # state: latest + # when: ansible_distribution == redhat_os_name|string and ansible_distribution_major_version == '7' + # tags: + # - packages - name: Ensures "nice to have" packages are present package: From 29dc4ef5e6c3d5a4b099cccda377edaefe7c4cbc Mon Sep 17 00:00:00 2001 From: kevinlinglesas <36995745+kevinlinglesas@users.noreply.github.com> Date: Tue, 13 Aug 2019 18:32:42 -0400 Subject: [PATCH 15/17] Updating CHANGELOG regarding systemd issues. --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ee0ae3..a527cad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog for SAS Viya-ARK +## Viya34-ark-1.6 - August 13, 2019 + +- **Summary**: + Temporary workaround for issues related to updating systemd to latest (currently version 219-67) +- Issues addressed: + - DEPENB-2009 - Do not update systemd on RHEL7 with pre-install playbook. +- Ansible Support: Ansible 2.5 - Ansible 2.7 + + + ## Viya34-ark-1.5 - July 11, 2019 - **Summary**: @@ -14,8 +24,6 @@ - DEPENB-1857 - Host group name references with hyphens changed to underscores. Future Ansible version compliance. - Ansible Support: Ansible 2.5 - Ansible 2.7 - - ## Viya34-ark-1.4 - June 5, 2019 - **Summary**: From f7171be005dc48ff87baed7925a8c3213fefdf28 Mon Sep 17 00:00:00 2001 From: kevinlinglesas <36995745+kevinlinglesas@users.noreply.github.com> Date: Fri, 28 Feb 2020 14:58:33 -0500 Subject: [PATCH 16/17] Update CHANGELOG.md Date correction. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3116595..02c6ab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changelog for SAS Viya ARK -## Viya35-ark-1.2 - February 28, 2019 +## Viya35-ark-1.2 - February 28, 2020 - **Summary**: Enhancements and fixes related to Upgrade, Multi-Machine Services Utilities, Deployment Report, Pre-Installation playbooks and documentation. - Issues addressed: From c5d60682fa1a533675aea15fadcc5e1445557a1e Mon Sep 17 00:00:00 2001 From: kevinlinglesas <36995745+kevinlinglesas@users.noreply.github.com> Date: Wed, 1 Apr 2020 17:20:52 -0400 Subject: [PATCH 17/17] Update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784cd40..1db0bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,6 @@ # Changelog for SAS Viya ARK -<<<<<<< HEAD ## Viya35-ark-1.3 - April 1, 2020 - **Summary**: Enhancements and fixes related to Upgrade, Multi-Machine Services Utilities, Pre-Installation playbooks.