From 41b040db52789af73c126478cdf308d7b68ef885 Mon Sep 17 00:00:00 2001 From: Oussama Jamal Date: Wed, 20 Nov 2024 21:19:01 +0100 Subject: [PATCH] Initialize ol9-main Signed-off-by: Oussama Jamal --- bin/oci-attached-volumes | 15 - bin/oci-network-config | 2 +- buildrpm/oci-utils.spec | 39 +- data/91-oci-utils.preset | 2 +- data/oci-migrate-conf.yaml | 16 +- etc/rsyslog.d/12-oci-utils.conf | 2 + lib/oci_utils/__init__.py | 4 +- lib/oci_utils/impl/__init__.py | 3 + lib/oci_utils/impl/network_helpers.py | 127 +- lib/oci_utils/impl/network_interface.py | 45 +- .../impl/oci_attached_volumes_main.py | 483 --- lib/oci_utils/impl/oci_iscsi_config_main.py | 3301 ++++++++--------- lib/oci_utils/impl/oci_network_config_main.py | 1569 ++++---- lib/oci_utils/impl/oci_notify_main.py | 172 +- lib/oci_utils/impl/oci_resources.py | 9 +- lib/oci_utils/impl/oci_test_ip_auth_main.py | 18 +- lib/oci_utils/impl/ocid_main.py | 106 +- lib/oci_utils/impl/row_printer_helpers.py | 10 - lib/oci_utils/impl/virt/sysconfig.py | 9 +- lib/oci_utils/impl/virt/virt_check.py | 4 +- lib/oci_utils/iscsiadm.py | 2 +- lib/oci_utils/kvm/virt.py | 175 +- lib/oci_utils/metadata.py | 1 + lib/oci_utils/migrate/reconfigure_network.py | 2 +- lib/oci_utils/vnicutils.py | 17 +- libexec/oci-image-cleanup | 4 +- libexec/oci-image-expand | 678 ++++ libexec/oci-utils-config-helper | 57 + man/man1/oci-attached-volumes.1 | 83 - man/man1/oci-notify.1 | 8 +- setup.py | 2 - tests/automation/Makefile | 169 - tests/automation/__init__.py | 0 tests/automation/configuration/BUILD.txt | 36 - tests/automation/configuration/README.txt | 24 - .../configuration/RPM-GPG-KEY-oracle-7 | 19 - .../configuration/RPM-GPG-KEY-oracle-8 | 52 - .../configuration/oci-utils-automation.repo-7 | 6 - .../configuration/oci-utils-automation.repo-8 | 6 - .../configuration/oci-utils-automation.spec | 95 - tests/automation/create_lvm | 148 - tests/automation/create_user | 216 -- tests/automation/create_volume | 90 - tests/automation/data/LICENSE.txt | 6 - tests/automation/data/README.md | 4 - tests/automation/data/base_instance/data.tf | 7 - tests/automation/data/base_instance/main.tf | 215 -- tests/automation/data/base_instance/output.tf | 21 - .../scripts/install_oci_utils_automation.sh | 45 - .../install_oci_utils_kvm_automation.sh | 48 - tests/automation/data/test_iscsi/data.tf | 8 - tests/automation/data/test_iscsi/main.tf | 169 - .../data/test_iscsi/terraform_version.tf | 10 - tests/automation/data/test_metadata/data.tf | 8 - tests/automation/data/test_metadata/main.tf | 169 - .../data/test_metadata/terraform_version.tf | 10 - tests/automation/data/test_various/data.tf | 8 - tests/automation/data/test_various/main.tf | 259 -- .../data/test_various/terraform_version.tf | 10 - tests/automation/data/userdata/tests-env | 13 - tests/automation/data/userdata/tests-resolve | 7 - tests/automation/oci_utils_configure_tests.py | 1195 ------ tests/automation/oci_utils_iscsi_data.py | 111 - tests/automation/oci_utils_network_data.py | 100 - tests/automation/oci_utils_pool_data.py | 98 - tests/automation/oci_utils_test_instance.py | 1508 -------- tests/automation/templates/tf_apikey | 41 - tests/automation/templates/tf_data | 7 - tests/automation/templates/tf_main | 157 - tests/automation/templates/tf_output | 19 - tests/automation/templates/tf_test | 20 - tests/automation/templates/tf_version | 9 - tests/test_cli_iscsi_config_create.py | 18 +- tests/test_cli_metadata.py | 1 + tests/test_cli_network_config_attach.py | 9 +- tests/test_cli_network_config_configure.py | 84 +- tests/test_oci_growfs.py | 2 +- tests/test_oci_volume.py | 1 + tools/decorators.py | 2 + tools/kvm-schema.yaml_save | 288 -- tools/kvm_image/build_image/Makefile | 198 - tools/kvm_image/build_image/README.md | 173 - .../build_image/bin/configure_image.py | 883 ----- .../build_image/bin/create_imagebuild | 203 - .../build_image/bin/install_packer.py | 205 - .../kvm_image/build_image/bin/upload_image.py | 465 --- .../build_image/scripts/custom_firstboot.sh | 5 - .../build_image/scripts/custom_install.sh | 23 - .../scripts/custom_post_install_task.sh | 103 - .../templates/al-kvm-image-template.json | 71 - .../templates/ol-kvm-image-template.json | 66 - tools/kvm_image/test_image/Makefile | 163 - tools/kvm_image/test_image/README.md | 106 - .../test_image/bin/create_kvmhost_user | 245 -- .../create_kvm_instance.0.11_May_05_2022.bz2 | Bin 21192 -> 0 bytes .../guest_instance/bin/create_guest_vm | 16 - .../guest_instance/bin/create_guest_vm.py | 859 ----- .../templates/kickstart_bridge_template_ol7 | 62 - .../templates/kickstart_bridge_template_ol8 | 61 - .../templates/kickstart_bridge_template_ol9 | 61 - .../templates/kickstart_direct_template_ol7 | 62 - .../templates/kickstart_direct_template_ol8 | 61 - .../templates/kickstart_direct_template_ol9 | 61 - .../host_instance/base_instance/data.tf | 3 - .../host_instance/base_instance/main.tf | 210 -- .../host_instance/base_instance/output.tf | 24 - .../host_instance/bin/create_kvm_host | 16 - .../host_instance/bin/create_kvm_host.py | 1741 --------- .../sh_scripts/initial_config.sh | 36 - .../host_instance/tf_scripts/api_key.tf | 47 - .../host_instance/tf_scripts/data.tf | 8 - .../host_instance/tf_scripts/main.tf | 163 - .../host_instance/tf_scripts/output.tf | 19 - .../host_instance/tf_scripts/rsa_key.tf | 40 - .../host_instance/tf_scripts/rsa_pub_key.tf | 40 - .../host_instance/tf_scripts/version.tf | 9 - tools/provisioning/gen_instance/Makefile | 134 - tools/provisioning/gen_instance/README.md | 40 - .../gen_instance/base_instance/data.tf | 3 - .../gen_instance/base_instance/main.tf | 210 -- .../gen_instance/base_instance/output.tf | 24 - .../gen_instance/bin/create_instance | 13 - .../gen_instance/bin/create_instance.py | 1759 --------- .../gen_scripts/initial_config.sh | 151 - .../gen_instance/tf_scripts/api_key.tf | 47 - .../gen_instance/tf_scripts/data.tf | 8 - .../gen_instance/tf_scripts/main.tf | 163 - .../gen_instance/tf_scripts/output.tf | 19 - .../gen_instance/tf_scripts/rsa_key.tf | 40 - .../gen_instance/tf_scripts/rsa_pub_key.tf | 40 - .../gen_instance/tf_scripts/version.tf | 9 - tools/provisioning/kvm_instance/Makefile | 126 - tools/provisioning/kvm_instance/README.md | 42 - .../kvm_instance/base_instance/data.tf | 3 - .../kvm_instance/base_instance/main.tf | 204 - .../kvm_instance/base_instance/output.tf | 24 - .../kvm_instance/bin/create_kvm_instance | 14 - .../kvm_instance/bin/create_kvm_instance.py | 1695 --------- .../gen_scripts/initial_config.sh | 106 - .../kvm_instance/tf_scripts/api_key.tf | 41 - .../kvm_instance/tf_scripts/data.tf | 8 - .../kvm_instance/tf_scripts/main.tf | 157 - .../kvm_instance/tf_scripts/output.tf | 19 - .../kvm_instance/tf_scripts/version.tf | 9 - usr/share/man/man8/oci-image-expand.8 | 103 + 145 files changed, 3522 insertions(+), 20710 deletions(-) delete mode 100755 bin/oci-attached-volumes create mode 100644 etc/rsyslog.d/12-oci-utils.conf delete mode 100644 lib/oci_utils/impl/oci_attached_volumes_main.py create mode 100644 libexec/oci-image-expand delete mode 100644 man/man1/oci-attached-volumes.1 delete mode 100644 tests/automation/Makefile delete mode 100644 tests/automation/__init__.py delete mode 100644 tests/automation/configuration/BUILD.txt delete mode 100644 tests/automation/configuration/README.txt delete mode 100644 tests/automation/configuration/RPM-GPG-KEY-oracle-7 delete mode 100644 tests/automation/configuration/RPM-GPG-KEY-oracle-8 delete mode 100644 tests/automation/configuration/oci-utils-automation.repo-7 delete mode 100644 tests/automation/configuration/oci-utils-automation.repo-8 delete mode 100644 tests/automation/configuration/oci-utils-automation.spec delete mode 100644 tests/automation/create_lvm delete mode 100755 tests/automation/create_user delete mode 100644 tests/automation/create_volume delete mode 100644 tests/automation/data/LICENSE.txt delete mode 100644 tests/automation/data/README.md delete mode 100644 tests/automation/data/base_instance/data.tf delete mode 100644 tests/automation/data/base_instance/main.tf delete mode 100644 tests/automation/data/base_instance/output.tf delete mode 100644 tests/automation/data/scripts/install_oci_utils_automation.sh delete mode 100644 tests/automation/data/scripts/install_oci_utils_kvm_automation.sh delete mode 100644 tests/automation/data/test_iscsi/data.tf delete mode 100644 tests/automation/data/test_iscsi/main.tf delete mode 100644 tests/automation/data/test_iscsi/terraform_version.tf delete mode 100644 tests/automation/data/test_metadata/data.tf delete mode 100644 tests/automation/data/test_metadata/main.tf delete mode 100644 tests/automation/data/test_metadata/terraform_version.tf delete mode 100644 tests/automation/data/test_various/data.tf delete mode 100644 tests/automation/data/test_various/main.tf delete mode 100644 tests/automation/data/test_various/terraform_version.tf delete mode 100644 tests/automation/data/userdata/tests-env delete mode 100644 tests/automation/data/userdata/tests-resolve delete mode 100755 tests/automation/oci_utils_configure_tests.py delete mode 100755 tests/automation/oci_utils_iscsi_data.py delete mode 100755 tests/automation/oci_utils_network_data.py delete mode 100755 tests/automation/oci_utils_pool_data.py delete mode 100755 tests/automation/oci_utils_test_instance.py delete mode 100644 tests/automation/templates/tf_apikey delete mode 100644 tests/automation/templates/tf_data delete mode 100644 tests/automation/templates/tf_main delete mode 100644 tests/automation/templates/tf_output delete mode 100644 tests/automation/templates/tf_test delete mode 100644 tests/automation/templates/tf_version delete mode 100644 tools/kvm-schema.yaml_save delete mode 100644 tools/kvm_image/build_image/Makefile delete mode 100644 tools/kvm_image/build_image/README.md delete mode 100755 tools/kvm_image/build_image/bin/configure_image.py delete mode 100755 tools/kvm_image/build_image/bin/create_imagebuild delete mode 100755 tools/kvm_image/build_image/bin/install_packer.py delete mode 100755 tools/kvm_image/build_image/bin/upload_image.py delete mode 100644 tools/kvm_image/build_image/scripts/custom_firstboot.sh delete mode 100644 tools/kvm_image/build_image/scripts/custom_install.sh delete mode 100644 tools/kvm_image/build_image/scripts/custom_post_install_task.sh delete mode 100644 tools/kvm_image/build_image/templates/al-kvm-image-template.json delete mode 100644 tools/kvm_image/build_image/templates/ol-kvm-image-template.json delete mode 100644 tools/kvm_image/test_image/Makefile delete mode 100644 tools/kvm_image/test_image/README.md delete mode 100755 tools/kvm_image/test_image/bin/create_kvmhost_user delete mode 100644 tools/kvm_image/test_image/create_kvm_instance.0.11_May_05_2022.bz2 delete mode 100755 tools/kvm_image/test_image/guest_instance/bin/create_guest_vm delete mode 100755 tools/kvm_image/test_image/guest_instance/bin/create_guest_vm.py delete mode 100644 tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol7 delete mode 100644 tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol8 delete mode 100644 tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol9 delete mode 100644 tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol7 delete mode 100644 tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol8 delete mode 100644 tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol9 delete mode 100644 tools/kvm_image/test_image/host_instance/base_instance/data.tf delete mode 100644 tools/kvm_image/test_image/host_instance/base_instance/main.tf delete mode 100644 tools/kvm_image/test_image/host_instance/base_instance/output.tf delete mode 100755 tools/kvm_image/test_image/host_instance/bin/create_kvm_host delete mode 100755 tools/kvm_image/test_image/host_instance/bin/create_kvm_host.py delete mode 100644 tools/kvm_image/test_image/host_instance/sh_scripts/initial_config.sh delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/api_key.tf delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/data.tf delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/main.tf delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/output.tf delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/rsa_key.tf delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/rsa_pub_key.tf delete mode 100644 tools/kvm_image/test_image/host_instance/tf_scripts/version.tf delete mode 100644 tools/provisioning/gen_instance/Makefile delete mode 100644 tools/provisioning/gen_instance/README.md delete mode 100644 tools/provisioning/gen_instance/base_instance/data.tf delete mode 100644 tools/provisioning/gen_instance/base_instance/main.tf delete mode 100644 tools/provisioning/gen_instance/base_instance/output.tf delete mode 100644 tools/provisioning/gen_instance/bin/create_instance delete mode 100755 tools/provisioning/gen_instance/bin/create_instance.py delete mode 100644 tools/provisioning/gen_instance/gen_scripts/initial_config.sh delete mode 100644 tools/provisioning/gen_instance/tf_scripts/api_key.tf delete mode 100644 tools/provisioning/gen_instance/tf_scripts/data.tf delete mode 100644 tools/provisioning/gen_instance/tf_scripts/main.tf delete mode 100644 tools/provisioning/gen_instance/tf_scripts/output.tf delete mode 100644 tools/provisioning/gen_instance/tf_scripts/rsa_key.tf delete mode 100644 tools/provisioning/gen_instance/tf_scripts/rsa_pub_key.tf delete mode 100644 tools/provisioning/gen_instance/tf_scripts/version.tf delete mode 100644 tools/provisioning/kvm_instance/Makefile delete mode 100644 tools/provisioning/kvm_instance/README.md delete mode 100644 tools/provisioning/kvm_instance/base_instance/data.tf delete mode 100644 tools/provisioning/kvm_instance/base_instance/main.tf delete mode 100644 tools/provisioning/kvm_instance/base_instance/output.tf delete mode 100644 tools/provisioning/kvm_instance/bin/create_kvm_instance delete mode 100755 tools/provisioning/kvm_instance/bin/create_kvm_instance.py delete mode 100644 tools/provisioning/kvm_instance/gen_scripts/initial_config.sh delete mode 100644 tools/provisioning/kvm_instance/tf_scripts/api_key.tf delete mode 100644 tools/provisioning/kvm_instance/tf_scripts/data.tf delete mode 100644 tools/provisioning/kvm_instance/tf_scripts/main.tf delete mode 100644 tools/provisioning/kvm_instance/tf_scripts/output.tf delete mode 100644 tools/provisioning/kvm_instance/tf_scripts/version.tf create mode 100644 usr/share/man/man8/oci-image-expand.8 diff --git a/bin/oci-attached-volumes b/bin/oci-attached-volumes deleted file mode 100755 index 1314abeb..00000000 --- a/bin/oci-attached-volumes +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - -# utility verifies if instance principal authentication with OCI is -# configured correctly to create a working oci session. - -_PY3=/usr/bin/python3 -_PY_CMD=oci_attached_volumes_main.py -s_dir=`${_PY3} -c 'import os.path ; import oci_utils.impl ; print (os.path.dirname(oci_utils.impl.__file__))' 2>/dev/null` - -exec ${_PY3} ${s_dir}/${_PY_CMD} "$@" - diff --git a/bin/oci-network-config b/bin/oci-network-config index 5451715c..5fd31ac9 100755 --- a/bin/oci-network-config +++ b/bin/oci-network-config @@ -178,7 +178,7 @@ then cmd_line="$cmd_line --ip-address=${PRIVATE_IP}" fi # else -# echo "${COMMAND} handled elsewhere" +# echo "_GT_ ${COMMAND} handled elsewhere" fi if [ ${EXCLUDED_ITEMS[${COMMAND}]+_} ] && [ -n "${EXCLUDED_ITEMS[${COMMAND}]}" ] diff --git a/buildrpm/oci-utils.spec b/buildrpm/oci-utils.spec index 9afb0e0a..ace7fb65 100644 --- a/buildrpm/oci-utils.spec +++ b/buildrpm/oci-utils.spec @@ -1,10 +1,11 @@ Name: oci-utils Version: 0.14.0 -Release: 3%{?dist} +Release: 8%{?dist} Url: http://cloud.oracle.com/iaas Summary: Oracle Cloud Infrastructure utilities License: UPL Group: Development/Tools + Source: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot @@ -135,6 +136,12 @@ Utilities migrate unit tests %{__cp} -r setup.py %{buildroot}/opt/oci-utils %{__cp} -r requirements.txt %{buildroot}/opt/oci-utils %{__cp} -r README.md %{buildroot}/opt/oci-utils +# oci-image-expand files +%{__mkdir_p} %{buildroot}%{_sysconfdir}/rsyslog.d +%{__mkdir_p} %{buildroot}%{_libexecdir} +%{__cp} -r etc/rsyslog.d/12-oci-utils.conf %{buildroot}%{_sysconfdir}/rsyslog.d/. +%{__cp} -r libexec/oci-image-expand %{buildroot}%{_libexecdir}/. +%{__cp} -r usr/share/man/man8/oci-image-expand.8 %{buildroot}%{_datadir}/man/man8/. %clean rm -rf %{buildroot} @@ -164,6 +171,10 @@ rm -rf %{buildroot} %exclude %{_datadir}/man/man1/oci-kvm.1.gz %dir %{_localstatedir}/lib/oci-utils %doc LICENSE.txt PKG-INFO +# oci-image-expand files +%attr(644,root,root) %{_sysconfdir}/rsyslog.d/12-oci-utils.conf +%attr(755,root,root) %{_libexecdir}/oci-image-expand +%attr(644,root,root) %{_datadir}/man/man8/oci-image-expand.8.gz %files kvm %{_bindir}/oci-kvm @@ -179,6 +190,10 @@ rm -rf %{buildroot} %exclude /opt/oci-utils/tests/test_mig* /opt/oci-utils +%post +# Need to restart the rsyslogd service when the RPM is installed or upgraded +/bin/systemctl restart rsyslog.service + %post kvm %systemd_post oci-kvm-config.service @@ -206,10 +221,24 @@ rm -rf %{buildroot} /opt/oci-utils/tests/__init__* %changelog -* Thu Sep 22 2022 Guido Tijskens -- 0.14.0-3 -- LINUX-11440/LINUX-12246 iscsi does not fall back to scanning if authentication succeeds but get instance data fails -- added oci-attached-volumes, collects data on volumes, via OCI if priviliges in place, via scan otherwise. -- LINUX-12907 sudo oci-network-config --show missing spaces between values +* Mon Oct 14 2024 Jesse Gordon -- 0.14.0-8 +- oci-network-config: fix for too long VNIC names [Orabug: 36991547] + +* Tue Jul 30 2024 Jesse Gordon -- 0.14.0-7 +- oci-image-expand: new utility to restore functionality, with conf file for logging and a man page [Orabug: 36223392] + +* Thu Jul 11 2024 Oussama Jamal -- 0.14.0-6 +- oci-kvm: add patch information for the iommu_check fix [Orabug: 36380825] + +* Thu Jun 20 2024 Oussama Jamal -- 0.14.0-5 +- oci-kvm: fix the iommu_check failure [Orabug: 36380825] + +* Tue Sep 5 2023 Kaylin Devchand -- 0.14.0-4 +- oci-image-cleanup: preserve oci.sh [Orabug: 35766360] +- oci-image-cleanup: remove backup log directories [Orabug: 35766353] + +* Mon Aug 7 2023 Oussama Jamal -- 0.14.0-3 +- Make ocid vendor preset disabled [Orabug: 35683717] * Mon Sep 5 2022 Guido Tijskens -- 0.14.0-2 - LINUX-12761/OLUEK-6199 ocid leaves lots of connections in CLOSE_WAIT state diff --git a/data/91-oci-utils.preset b/data/91-oci-utils.preset index 8866769e..e06f4645 100644 --- a/data/91-oci-utils.preset +++ b/data/91-oci-utils.preset @@ -2,4 +2,4 @@ # https://fedoraproject.org/wiki/Starting_services_by_default # ocid -enable ocid.service +disable ocid.service diff --git a/data/oci-migrate-conf.yaml b/data/oci-migrate-conf.yaml index e5010610..e077526d 100644 --- a/data/oci-migrate-conf.yaml +++ b/data/oci-migrate-conf.yaml @@ -294,9 +294,9 @@ ol_os_oci_region_bash : - '#!/bin/bash' - unset http_proxy - unset https_proxy - - CURL=$(command -v curl) - - JQ=$(command -v jq) - - CUT=$(command -v cut) + - CURL=$(which curl) + - JQ=$(which jq) + - CUT=$(which cut) - METADATAURL="http://169.254.169.254" - OCIREGION=$(${CURL} -sfm 5 ${METADATAURL}/opc/v1/instance/ | ${JQ} -r '.region' | ${CUT} -d '-' -f 2) - echo '-'$OCIREGION > /etc/yum/vars/ociregion @@ -313,9 +313,9 @@ ubuntu_os_snapd_bash: - '#!/bin/bash' - SNAPD='snapd' - snaplist=_XXXX_ - - SNAP=$(command -v snap) - - SYSCTL=$(command -v systemctl) - - LOGGER=$(command -v logger) + - SNAP=$(which snap) + - SYSCTL=$(which systemctl) + - LOGGER=$(which logger) - ${SYSCTL} enable ${SNAPD} - ${SYSCTL} start ${SNAPD} - snapdstatus=$(${SYSCTL} status ${SNAPD}) @@ -338,8 +338,8 @@ reinitialise_cloud_init_script : /usr/local/bin/reinitialise_cloud_init.sh reinitialise_cloud_init: - '#!/bin/bash' - CLOUDINIT='cloud-init' - - RM=$(command -v rm) - - SYSTEMCTL=$(command -v systemctl) + - RM=$(which rm) + - SYSTEMCTL=$(which systemctl) - VARLIBCLOUD='/var/lib/cloud/' - VARLOGCLOUD='/var/log/cloud' - ${RM} -rf "${VARLIBCLOUD}*" diff --git a/etc/rsyslog.d/12-oci-utils.conf b/etc/rsyslog.d/12-oci-utils.conf new file mode 100644 index 00000000..6363d01c --- /dev/null +++ b/etc/rsyslog.d/12-oci-utils.conf @@ -0,0 +1,2 @@ +:syslogtag, startswith, "oci-image-expand" /var/log/oci-image-expand.log +& stop diff --git a/lib/oci_utils/__init__.py b/lib/oci_utils/__init__.py index e71d779d..c5d8fad6 100644 --- a/lib/oci_utils/__init__.py +++ b/lib/oci_utils/__init__.py @@ -159,7 +159,9 @@ def is_root_user(): ------- bool: True if root, False otherwise. """ - return bool(os.getuid() == 0) + if os.geteuid() != 0: + return False + return True def get_os_release_data(): diff --git a/lib/oci_utils/impl/__init__.py b/lib/oci_utils/impl/__init__.py index 09601dce..7cdd978b 100644 --- a/lib/oci_utils/impl/__init__.py +++ b/lib/oci_utils/impl/__init__.py @@ -39,6 +39,9 @@ SYSTEMCTL_CMD = '/bin/systemctl' LSBLK_CMD = '/bin/lsblk' +IF_NAME_PREFIX = 'vlan' +MACVLAN_IF_NAME_PREFIX = 'macvlan' + def print_choices(header, choices, sep="\n "): """ diff --git a/lib/oci_utils/impl/network_helpers.py b/lib/oci_utils/impl/network_helpers.py index 1e938295..b40911e1 100644 --- a/lib/oci_utils/impl/network_helpers.py +++ b/lib/oci_utils/impl/network_helpers.py @@ -221,14 +221,11 @@ def create_network_namespace(name): def destroy_network_namespace(name): """ Destroy network namespace - - Parameters - ---------- + parameter: name : namespace name as str - - Raises - ------ - Exception :in case of error + raise: + exception :in case of error + return none """ _logger.debug('%s: %s', where_am_i(), name) ret = sudo_utils.call([IP_CMD, 'netns', 'delete', name]) @@ -239,9 +236,7 @@ def destroy_network_namespace(name): def _get_namespaces(): """ Gets list of network namespace - - Returns - ------- + Returns: list of namespaces """ _logger.debug('%s', where_am_i()) @@ -399,7 +394,6 @@ def _get_link_infos(namespace): def get_network_namespace_infos(): """ Retrieve par namespace network link info - Returns: -------- dict: namespace name indexed dict (can be empty) with per namespadce all link info as dict @@ -567,7 +561,6 @@ def add_route_table(table_name): Adds a new routing table by name Add a new entry in /etc/iproute2/rt_tables If a table of that name already exists, silently abort the operation - Parameters ---------- table_name : str @@ -616,7 +609,6 @@ def delete_route_table(table_name): """ Deletes a routing table by name remove a entry in /etc/iproute2/rt_tables - Parameters ---------- table_name : str @@ -652,9 +644,7 @@ def delete_route_table(table_name): def network_prefix_to_mask(prefix): """ Converts an ipv4 prefix to a netmask address - - Parameters - ---------- + Parameters: prefix: int the prefix Returns: @@ -671,12 +661,10 @@ def remove_static_ip_route4(link_name): """ Deletes all ipv4 routes related to a network device. - Parameter - ---------- + Parameters: link_name : str the ip link name - Returns - ------ + Return: None """ _logger.debug('%s: %s', where_am_i(), link_name) @@ -700,12 +688,10 @@ def remove_static_ip_route6(link_name): """ Deletes all ipv6 routes related to a network device. - Parameter - ---------- + Parameters: link_name : str the ip link name - Returns - ------ + Return: None """ _logger.debug('%s: %s', where_am_i(), link_name) @@ -728,12 +714,10 @@ def remove_static_ip_routes(link_name): """ Deletes all routes related to a network device. - Parameters - ---------- + Parameters: link_name : str the ip link name - Returns - ------ + Return: None """ _logger.debug('%s: %s', where_am_i(), link_name) @@ -747,14 +731,12 @@ def add_static_ip_route4(*args, **kwargs): """ Add a static ipv4 route - Parameter - ---------- + Parameters: kwargs: namespace : network namespace in which to create the rule args : argument list as passed to the ip-route(8) command - Returns - ------ + Return: (code,message): command code , on failure a message is sent back """ _logger.debug('%s: \n%s\n%s', where_am_i(), args, kwargs) @@ -765,14 +747,12 @@ def add_static_ip_route6(*args, **kwargs): """ Add a static ipv6 route - Parameter - ---------- + Parameters: kwargs: namespace : network namespace in which to create the rule args : argument list as passed to the ip-route(8) command - Returns - ------ + Return: (code,message): command code , on failure a message is sent back """ _logger.debug('%s: \n%s\n%s', where_am_i(), args, kwargs) @@ -783,16 +763,14 @@ def add_static_ip_route(route_cmd, *args, **kwargs): """ Add a static route - Parameter - ---------- + Parameters: route_cmd: list version specific ip route command. kwargs: namespace : network namespace in which to create the rule args : argument list as passed to the ip-route(8) command - Returns - ------ + Return: (code,message): command code , on failure a message is sent back """ _logger.debug('%s: \n%s\n%s', where_am_i(), args, kwargs) @@ -827,11 +805,9 @@ def remove_mac_from_nm(mac): """ Removes given MAC addres from the ones managed by NetworkManager - Parameter - ---------- + Parameters: mac : the mac address as string - Returns - ------ + Return: None """ _logger.debug('%s: %s', where_am_i(), mac) @@ -862,11 +838,9 @@ def add_mac_to_nm(mac): """ Adds given MAC addres from the one managed by NetworkManager - Parameter - ---------- + Parameters: mac : the mac address as string - Returns - ------- + Return: None """ _logger.debug('%s: %s', where_am_i(), mac) @@ -881,16 +855,14 @@ def add_mac_to_nm(mac): def remove_ip_addr(device, ip_addr, namespace=None): """ Removes an IP address on a given device - - Parameters - ---------- + Parameter: device : network device as string ip_addr : the ip address as string [namespace]: network namespace as string - Returns - ------- + Return: None raise Exception : renmoval has failed + __GT__ nowhere used """ _logger.debug('%s: %s', where_am_i(), ip_addr) _cmd = [IP_CMD] @@ -906,12 +878,9 @@ def remove_ip_addr(device, ip_addr, namespace=None): def remove_ip_rules(ip_addr): """ Remove all ip rules set for an ip address - - Parameter - --------- + Parameter: ip_addr : the ip address as string - Returns - ------- + Return: None """ _logger.debug('%s: %s', where_am_i(), ip_addr) @@ -945,7 +914,6 @@ def remove_ip_rules(ip_addr): def remove_static_ip_rules46(link_name, ipversion): """ Delete all ipv4 or ipv6 rules related to a network device. - Parameters ---------- link_name: str @@ -984,13 +952,10 @@ def remove_static_ip_rules46(link_name, ipversion): def remove_static_ip_rules(link_name): """ Deletes all rules related to a network device - - Parameters - ---------- + Parameters: link_name : str the ip link name - Returns - ------- + Return: None """ _logger.debug('%s: %s', where_am_i(), link_name) @@ -1004,7 +969,6 @@ def remove_static_ip_rules(link_name): def add_static_ip_rule4(*args, **kwargs): """ Add a static rule for ipv4 address. - Parameters ---------- args: argument list as passed to the ip-rule(8) command @@ -1023,7 +987,6 @@ def add_static_ip_rule4(*args, **kwargs): def add_static_ip_rule6(*args, **kwargs): """ Add a static rule for ipv4 address. - Parameters ---------- args: argument list as passed to the ip-rule(8) command @@ -1041,17 +1004,14 @@ def add_static_ip_rule6(*args, **kwargs): def add_static_ip_rule(ip_cmd, *args, **kwargs): """ - Add a static rule - - Parameters - ---------- + add a static rule + Parameters: ip_cmd: str ip command with version. kwargs: device : network device on which assign the rule args : argument list as passed to the ip-rule(8) command - Return - ------ + Return: (code,message): command code , on failure a message is sent back """ _logger.debug('%s: %s', where_am_i(), args) @@ -1067,18 +1027,17 @@ def add_static_ip_rule(ip_cmd, *args, **kwargs): return 0, '' +# never called def add_firewall_rule(*args, **kwargs): """ - Add a static firewall rule - - Parameters - ---------- + add a static firewall rule + Parameters: kwargs: script : a reference to StringIO object to write the command for future use in script *args : argument list as passed to the iptables(8) command - Returns - ------- + Return: (code,message): command code , on failure a message is sent back + __GT__ nowhere used, virt?? """ _logger.debug('%s: \n%s\n%s', where_am_i(), args, kwargs) fw_rule_cmd = ['/usr/sbin/iptables'] @@ -1096,14 +1055,12 @@ def add_firewall_rule(*args, **kwargs): def remove_firewall_rule(*args): """ - Remove a static firewall rule - - Parameters - ---------- + remove a static firewall rule + Parameters: *args : argument list as passed to the iptables(8) command - Returns - ------- + Return: (code,message): command code , on failure a message is sent back + __GT__ used in virt ... need ipv6 version?? """ _logger.debug('%s: %s', where_am_i(), args) fw_rule_cmd = ['/usr/sbin/iptables'] @@ -1121,7 +1078,7 @@ def kill_processes_in_namespace(namespace): """ Kills remaining process within a network namespace - Parameters: + parameters: ----------- namespace : the namespace name as str Returns: diff --git a/lib/oci_utils/impl/network_interface.py b/lib/oci_utils/impl/network_interface.py index 0d01ebf8..353d3866 100644 --- a/lib/oci_utils/impl/network_interface.py +++ b/lib/oci_utils/impl/network_interface.py @@ -14,6 +14,7 @@ from oci_utils import where_am_i from . import IP_CMD +from . import IF_NAME_PREFIX, MACVLAN_IF_NAME_PREFIX from . import network_helpers as NetworkHelpers from . import sudo_utils from ..metadata import InstanceMetadata @@ -76,7 +77,6 @@ class NetworkInterfaceSetupHelper: def __init__(self, interface_info, namespace_name=None): """ Creates a new NetworkInterface - Parameters: ---------- interface_info : information about the interface as _intf_dict @@ -90,10 +90,9 @@ def __init__(self, interface_info, namespace_name=None): def setup(self): """ - Set up the interface. + Setup the interface. - Returns - ------- + Returns: No return value, raises an exception in case of error. """ _logger.debug('NetworkInterfaceSetupHelper %s', where_am_i()) @@ -109,8 +108,8 @@ def setup(self): # for BM case , create virtual interface if needed if _is_bm_shape and self.info['VLTAG'] != "0": - _vlan_name = '%sv%s' % (self.info['IFACE'], self.info['VLTAG']) - _macvlan_name = "%s.%s" % (self.info['IFACE'], self.info['VLTAG']) + _vlan_name = '%sv%s' % (IF_NAME_PREFIX, self.info['VLTAG']) + _macvlan_name = "%s%s" % (MACVLAN_IF_NAME_PREFIX, self.info['VLTAG']) _ip_cmd = [IP_CMD] if self.info.has('NS'): @@ -214,13 +213,10 @@ def setup(self): def tear_down(self): """ - Unconfigure the interface. - - Returns - ------- + unconfigure the interface. + returns: None - Raises - ------ + raises: Exception in case of error """ _logger.debug('NetworkInterfaceSetupHelper %s\n%s', where_am_i(), pformat(self.info, indent=4)) @@ -231,7 +227,10 @@ def tear_down(self): if self.info.has('VLAN'): # delete vlan and macvlan, removes the addrs (pri and sec) as well - _macvlan_name = "%s.%s" % (self.info['IFACE'], self.info['VLTAG']) + if IF_NAME_PREFIX in self.info['VLAN']: + _macvlan_name = MACVLAN_IF_NAME_PREFIX + self.info['VLTAG'] + else: # original naming scheme + _macvlan_name = self.info['IFACE'] + "." + self.info['VLTAG'] _ip_cmd.extend(['link', 'del', 'link', self.info['VLAN'], 'dev', _macvlan_name]) _logger.debug('Deleting macvlan [%s]', _macvlan_name) ret = sudo_utils.call(_ip_cmd) @@ -256,13 +255,10 @@ def add_secondary_address(self, ip_address): """ Add a secondary ip address ro this interface Add it to VLAN or device according to this being VLANed or not - - Parameters - ---------- - ip_address: the IP to be removed as str - Raise - ----- - Exception : in case of error during removal + parameter: + ip_address: the IP to be removed as str + raise: + Exception : in case of error during removal """ _logger.debug('%s: %s', where_am_i(), ip_address) if self.info.has('VLAN'): @@ -288,13 +284,10 @@ def remove_secondary_address(self, ip_address): """ Remove a secondary ip address from this interface Remove it from VLAN or device according to this being VLANed or not - Parameters - ---------- + parameter: ip_address: the IP to be removed as str - - Raise - ----- - Exception : in case of error during removal + raise: + Exception : in case of error during removal """ _logger.debug('%s: %s', where_am_i(), ip_address) if self.info.has('VLAN'): diff --git a/lib/oci_utils/impl/oci_attached_volumes_main.py b/lib/oci_utils/impl/oci_attached_volumes_main.py deleted file mode 100644 index 3bfec272..00000000 --- a/lib/oci_utils/impl/oci_attached_volumes_main.py +++ /dev/null @@ -1,483 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -# - -import argparse -import json -import logging -import os -import re -import socket -import subprocess -import sys -import urllib - -from oci_utils import oci_api -from oci_utils.iscsiadm import discovery - -try: - import oci as oci_sdk -except ImportError as e: - print('OCI SDK is not installed: %s.' % str(e)) - sys.exit(1) - -MAX_VOLUMES = 36 -_logger = logging.getLogger('oci-attached_volumes') - - -def def_usage_parser(s_parser): - """ - Define the usage parser. - - Parameters - ---------- - s_parser: subparsers. - - Returns - ------- - ArgumentParser: the usage subcommand parser. - """ - usage_parser = s_parser.add_parser('usage', - description='Displays usage', - help='Displays usage' - ) - return usage_parser - - -def def_attached_parser(s_parser): - """ - Define the attached subparser. - - Parameters - ---------- - s_parser: subparsers. - - Returns - ------- - ArgumentParser: the attached subcommand parser. - """ - attached_parser = s_parser.add_parser('attached', - description='Show only the attached volumes.', - help='Show data of the attached volumes.') - iqnall = attached_parser.add_mutually_exclusive_group(required=True) - iqnall.add_argument('-i', '--iqn', - action='store_true', - default=False, - help='Show only iqn.') - iqnall.add_argument('-a', '--all', - action='store_true', - help='Show all data.') - attached_parser.add_argument('-o', '--output-mode', - choices=('text', 'json', 'parsable'), - default='text', - help='Output mode text or json format, only valid with --all.' - ) - return attached_parser - - -def def_all_volume_parser(s_parser): - """ - Define the all volumes parser. - - Parameters - ---------- - s_parser: subparsers. - - Returns - ------- - ArgumentParser: the attached subcommand parser - """ - all_volume_parser = s_parser.add_parser('all', - description='Show all volumes in availability domain.', - help='Show all volumes in the availability domain if correct privileges ' - 'are present.') - all_volume_parser.add_argument('-o', '--output-mode', - choices=('text', 'json'), - default='text', - help='Output mode text or json format.' - ) - - return all_volume_parser - - -def get_args_parser(): - """ - Parse the command line arguments and return an object representing the - command line (as returned by argparse's parse_args()). - - Returns - ------- - The commandline argparse namespace. - """ - parser = argparse.ArgumentParser(prog='oci-iscsi-config', - description='Utility for listing iSCSI volume data.' - ) - subparser = parser.add_subparsers(dest='command') - # - # usage - _ = def_usage_parser(subparser) - # - # attached volumes - _ = def_attached_parser(subparser) - # - # all volumes - _ = def_all_volume_parser(subparser) - - return parser - - -def get_instance_id(): - """ - Get the ocid of this instance from the metadata. - - Returns - ------- - str: the instance ocid - """ - url = 'http://169.254.169.254/opc/v2/instance/id' - try: - req = urllib.request.Request(url=url) - req.add_header('Authorization', 'Bearer Oracle') - response = urllib.request.urlopen(req) - instance_ocid = response.readline().decode('utf-8') - # print('--- %-35s: %s ---' % ('This instance instance_id', instance_ocid)) - return instance_ocid - except Exception as e: - # print('Failed to collect instance_id: %s' % str(e)) - sys.exit(1) - - -def get_compartment_id(): - """ - Get the ocid of the current compartment from the metadata. - - Returns - ------- - str: the compartment ocid - """ - url = 'http://169.254.169.254/opc/v2/instance/compartmentId' - try: - req = urllib.request.Request(url=url) - req.add_header('Authorization', 'Bearer Oracle') - response = urllib.request.urlopen(req) - compartment_ocid = response.readline().decode('utf-8') - # print('--- %-35s: %s ---' % ('This compartment compartment_id', compartment_ocid)) - return compartment_ocid - except Exception as e: - # print('Failed to collect compartment_id: %s' % str(e)) - sys.exit(1) - - -def test_collecting_instance_data(instance_ocid): - """ - Test the collection of the instance data. - - Parameters - ---------- - instance_ocid: str - The instance ocid - - Returns - ------- - instance.data on success, False otherwise. - """ - try: - signer = oci_sdk.auth.signers.InstancePrincipalsSecurityTokenSigner() - compute_client = oci_sdk.core.compute_client.ComputeClient(config={}, signer=signer) - instance_data = compute_client.get_instance(instance_id=instance_ocid).data - return instance_data - except Exception as e: - # not the correct IP authentication. - return False - - -def test_collecting_all_volumes_data(compartment_id): - """ - Test the collection of the data of all volumes in the compartment. - - Parameters - ---------- - compartment_id: str - The compartment id. - - Returns - ------- - volumes list on success, False otherwise. - """ - try: - signer = oci_sdk.auth.signers.InstancePrincipalsSecurityTokenSigner() - block_storage_client = oci_sdk.core.blockstorage_client.BlockstorageClient(config={}, signer=signer) - block_storage_data = oci_sdk.pagination.list_call_get_all_results(block_storage_client.list_volumes, - compartment_id=compartment_id).data - # print('--- Successfully verified Instance Principal Authentication for collecting all volumes data. ' - # 'Found %d volume(s).' % len(block_storage_data)) - return block_storage_data - except Exception as e: - print('Failed to collect all volume data: %s\nMissing the correct privilege.' % str(e)) - # traceback.print_exception(*sys.exc_info()) - return False - - -def scan_attached_volumes(): - """ - Scan ip address verifying if block volume attached. - - Returns - ------- - list: list of dicts with ip, port, iqn. - """ - all_iqns = list() - for r in range(MAX_VOLUMES + 1): - ipaddr = "169.254.2.%d" % (r + 1) - iqns = discovery(ipaddr) - # print(iqns) - for iqn in iqns: - vol = {'iqn': iqn, - 'ipaddr': ipaddr, - 'port': 3260} - all_iqns.append(vol) - return all_iqns - - -def test_collecting_attached_volume_data(compartment_ocid, instance_ocid, arguments): - """ - Test the collection of the data on attached volumes. - Parameters - ---------- - compartment_ocid: str - The compartment ocid. - instance_ocid: str - The instance ocid - arguments: namespace - The command line. - - Returns - ------- - Attached volumes list on success, False otherwise - """ - try: - v_att_list = oci_api.OCISession().this_instance().all_volumes() - - # signer = oci_sdk.auth.signers.InstancePrincipalsSecurityTokenSigner() - # compute_client = oci_sdk.core.compute_client.ComputeClient(config={}, signer=signer) - # v_att_list = oci_sdk.pagination.list_call_get_all_results(compute_client.list_volume_attachments, - # compartment_id=compartment_ocid, - # instance_id=instance_ocid).data - all_iqns = list() - for volume in v_att_list: - vol = {'iqn': volume.get_iqn(), - 'ipaddr': volume.get_portal_ip(), - 'port': volume.get_portal_port()} - if arguments.all: - vol['display_name'] = volume.get_display_name() - vol['ocid'] = volume.get_ocid() - # vol['created'] = str(volume.time_created) - # vol['volume_id'] = volume.volume_id - all_iqns.append(vol) - return all_iqns - except Exception as e: - print('Failed to collect attached volume data: %s\nShould not happen here.' % str(e)) - # traceback.print_exception(*sys.exc_info()) - return False - - -def print_par(tag, value, size): - """ - Print a variable lenght format string. - - Parameters - ---------- - tag: str - head - value: str - value - size: int - lenght - - Returns - ------- - No return value - """ - print(f"{tag:>{size}}: {value}") - - -def show_attached_volume_data(arguments, context): - """ - Show the data for attached volumes. - - Parameters - ---------- - arguments: namespace - The command line arguements. - - context: dict - The context. - - Returns - ------- - int: 0 on success, -1 on failure - """ - if context['instance_principal']: - attached_volumes = test_collecting_attached_volume_data(compartment_ocid=context['compartment_id'], - instance_ocid=context['instance_id'], - arguments=arguments) - else: - attached_volumes = scan_attached_volumes() - # - # scanning does only provide ip,port, iqn - arguments.iqn = True - - if arguments.iqn: - for volume in attached_volumes: - if arguments.output_mode == 'json': - print('%s' % json.dumps(volume, indent=4)) - elif arguments.output_mode == 'parsable': - print('#%s#%s#%s#' % - (volume['ipaddr'], - volume['port'], - volume['iqn'])) - elif arguments.output_mode == 'text': - print('%s:%s %s ' % - (volume['ipaddr'], - volume['port'], - volume['iqn'])) - else: - print('Missing output-mode parameter\n') - return -1 - elif arguments.all: - for volume in attached_volumes: - if arguments.output_mode == 'json': - print('%s' % json.dumps(volume, indent=4)) - elif arguments.output_mode == 'parsable': - print('#%s#%s#%s#%s#%s#' % - (volume['ipaddr'], - volume['port'], - volume['iqn'], - volume['display_name'], - volume['ocid'])) - elif arguments.output_mode == 'text': - print_par('ipaddr:port', '%s:%s' % (volume['ipaddr'], volume['port']), 12) - print_par('iqn', volume['iqn'], 20) - print_par('display name', volume['display_name'], 20) - print_par('ocid', volume['ocid'], 20) - else: - print('Missing output-mode parameter\n') - return -1 - else: - print('Missing iqn or all paramater') - return -1 - return 1 - - -def show_all_volume_data(volumes, args): - """ - Show data for all volumes in the availability domain. - - Parameters - ---------- - volumes: list - list of volume objects. - args: namespace - command line - - Returns - ------- - int: 0 on success, -1 otherwise. - """ - if args.output_mode == 'text': - for volume in volumes: - print_par('display name', volume.display_name, 12) - print_par('size', volume.size_in_gbs, 20) - print_par('ocid', volume.id, 20) - if 'Operations' in volume.defined_tags: - print_par('created by', volume.defined_tags['Operations']['CreateBy'], 20) - elif 'Oracle-Tags' in volume.defined_tags: - print_par('created by', volume.defined_tags['Oracle-Tags']['CreatedBy'], 20) - else: - print_par('created by', 'unknown', 20) - print_par('create time', str(volume.time_created), 20) - print_par('state', volume.lifecycle_state, 20) - elif args.output_mode == 'json': - all_vols = dict() - for volume in volumes: - all_vols[volume.display_name] = dict() - vol_data = dict() - vol_data['size'] = '%s GB' % volume.size_in_gbs - vol_data['ocid'] = volume.id - if 'Operations' in volume.defined_tags: - vol_data['created by'] = volume.defined_tags['Operations']['CreateBy'] - elif 'Oracle-Tags' in volume.defined_tags: - vol_data['created by'] = volume.defined_tags['Oracle-Tags']['CreatedBy'] - else: - vol_data['created by'] = 'unknown' - vol_data['create time'] = str(volume.time_created) - vol_data['state'] = volume.lifecycle_state - all_vols[volume.display_name] = vol_data - print('%s' % json.dumps(all_vols, indent=4)) - else: - print('Invalid output mode') - return -1 - return 0 - - -def main(): - """ - Test if Instance Principal Authentication is configured correctly. - - Returns - ------- - int - 0 on success, 1 otherwise. - """ - # - # command line - parser = get_args_parser() - args = parser.parse_args() - # - # no arguments defaults to usage - if args.command is None or args.command == 'usage': - parser.print_help() - sys.exit(0) - # - # the instance id from the metadata - instance_id = get_instance_id() - # - # the compartment id from the metadata - compartment_id = get_compartment_id() - # - # test the instance data collection - instance_info = test_collecting_instance_data(instance_id) - display_name = instance_info.display_name if instance_info else 'this instance' - # - # if instance info fails, unlikely instance principals are defined to collect all data from instance. - instance_principal = bool(instance_info) - # - context = dict() - context['instance_id'] = instance_id - context['compartment_id'] = compartment_id - context['display_name'] = display_name - context['instance_principal'] = instance_principal - # - # attached volumes - if args.command == 'attached': - if show_attached_volume_data(args, context) < 0: - parser.print_help() - # - # all volumes - if args.command == 'all': - if not instance_principal: - print('Missing privileges to collect data for all volumes.') - return -1 - # - # test the listing of all volumes in the compartment. - all_volumes = test_collecting_all_volumes_data(compartment_id) - if show_all_volume_data(all_volumes, args) < 0: - parser.print_help() - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/lib/oci_utils/impl/oci_iscsi_config_main.py b/lib/oci_utils/impl/oci_iscsi_config_main.py index bc91a2b8..839ea5b4 100644 --- a/lib/oci_utils/impl/oci_iscsi_config_main.py +++ b/lib/oci_utils/impl/oci_iscsi_config_main.py @@ -20,18 +20,14 @@ from datetime import timedelta import oci_utils.oci_api -from oci_utils import MAX_VOLUMES_LIMIT from oci_utils import OCI_VOLUME_SIZE_FMT +from oci_utils import MAX_VOLUMES_LIMIT from oci_utils import __chap_password_file from oci_utils import __ignore_file, iscsiadm, lsblk, is_root_user from oci_utils import _configuration as OCIUtilsConfiguration -from oci_utils import where_am_i from oci_utils.cache import load_cache, write_cache from oci_utils.cache import load_cache_11876, write_cache_11876 from oci_utils.impl.row_printer import get_row_printer_impl -from oci_utils.impl.row_printer_helpers import get_value_data -from oci_utils.impl.row_printer_helpers import initialise_column_lengths -from oci_utils.impl.row_printer_helpers import print_data from oci_utils.metadata import InstanceMetadata _logger = logging.getLogger("oci-utils.oci-iscsi-config") @@ -42,32 +38,131 @@ cache_delay = 65 -class IscsiConfigException(Exception): - """Class of exceptions during notification handling +def volume_size_validator(value): """ - def __init__(self, message=None): - """ - Initialisation of the Oci NetworkConfig Exception. + Validate than value passed is an int and greater than 50 (GB). - Parameters - ---------- - message: str - The exception message. - """ - super().__init__() - self._message = message - assert (self._message is not None), 'No exception message given, no further information.' + Parameters + ---------- + value: str + Size in GB. - def __str__(self): - """ - Get this OCISDKError representation. + Returns + ------- + int: size in GB on success. + """ + _i_value = 0 + try: + _i_value = int(value) + except ValueError as e: + raise argparse.ArgumentTypeError("Block volume size must be a int") from e - Returns - ------- - str - The error message. - """ - return str(self._message) + if _i_value < 50: + raise argparse.ArgumentTypeError("Volume size must be at least 50GBs") + return _i_value + + +def attachable_iqn_list_validator(value): + """ + Validate that value passed is a list of iqn and/or ocid. + + Parameters + ---------- + value: str + A comma separated list of iqn's. + + Returns + ------- + list: a list of iqn's. + """ + _iqns = [iqn.strip() for iqn in value.split(',') if iqn] + for iqn in _iqns: + if not iqn.startswith(iqn_tag) and not iqn.startswith(oci_volume_tag): + raise argparse.ArgumentTypeError('Invalid IQN %s' % iqn) + return _iqns + + +def detachable_iqn_list_validator(value): + """ + Validate the value passed is a list of iqn and does not contain boot volume. + + Parameters + ---------- + value: str + A comma separated list of iqn's. + + Returns + ------- + list: a list of iqn's. + """ + _iqns = [iqn.strip() for iqn in value.split(',') if iqn] + for iqn in _iqns: + if not iqn.startswith(iqn_tag): + raise argparse.ArgumentTypeError('Invalid IQN %s' % iqn) + if 'boot:uefi' in iqn: + raise argparse.ArgumentTypeError('Cannot detach boot volume IQN %s' % iqn) + return _iqns + + +def volume_oci_list_validator(value): + """ + Validate than value passed is a list of volume ocid's. + + Parameters + ---------- + value: str + A comma separated list of ocid's. + + Returns + ------- + list: a list of ocid's + """ + _ocids = [ocid.strip() for ocid in value.split(',') if ocid] + for ocid in _ocids: + if not ocid.startswith(oci_volume_tag): + raise argparse.ArgumentTypeError('Invalid volume OCID %s' % ocid) + return _ocids + + +def get_args_parser(): + """ + Parse the command line arguments and return an object representing the + command line (as returned by argparse's parse_args()). + + Returns + ------- + The commandline argparse namespace. + """ + parser = argparse.ArgumentParser(prog='oci-iscsi-config', + description='Utility for listing or configuring iSCSI devices on an OCI instance.' + ) + subparser = parser.add_subparsers(dest='command') + # + # usage + _ = def_usage_parser(subparser) + # + # sync + _ = def_sync_parser(subparser) + # + # show-all + _ = def_show_all_parser(subparser) + # + # show + _ = def_show_parser(subparser) + # + # create + _ = def_create_parser(subparser) + # + # attach + _ = def_attach_parser(subparser) + # + # detach + _ = def_detach_parser(subparser) + # + # destroy + _ = def_destroy_parser(subparser) + + return parser def def_usage_parser(s_parser): @@ -86,7 +181,7 @@ def def_usage_parser(s_parser): description='Displays usage', help='Displays usage' ) - # for compatibility mode + # for compatibility mode usage_parser.add_argument('--compat', action='store_true', default=False, @@ -108,9 +203,9 @@ def def_sync_parser(s_parser): ArgumentParser: the sync subcommand parser. """ sync_parser = s_parser.add_parser('sync', - description='Try to attach available block devices.', - help='Try to attach available block devices.' - ) + description='Try to attach available block devices.', + help='Try to attach available block devices.' + ) sync_parser.add_argument('-a', '--apply', action='store_true', default=False, @@ -264,11 +359,11 @@ def def_attach_parser(s_parser): ArgumentParser: the attach subcommand parser """ attach_parser = s_parser.add_parser('attach', - description='Attach a block volume to this instance ' - 'and make it available to the system.', - help='Attach a block volume to this instance ' - 'and make it available to the system.' - ) + description='Attach a block volume to this instance and make it available '\ + 'to the system.', + help='Attach a block volume to this instance and make it available to the '\ + 'system.' + ) ocidiqn = attach_parser.add_mutually_exclusive_group(required=True) ocidiqn.add_argument('-I', '--iqns', type=attachable_iqn_list_validator, @@ -316,9 +411,9 @@ def def_detach_parser(s_parser): ArgumentParser: the detach subcommand parser """ detach_parser = s_parser.add_parser('detach', - description='Detach a block volume', - help='Detach a block volume' - ) + description='Detach a block volume', + help='Detach a block volume' + ) detach_parser.add_argument('-I', '--iqns', required=True, type=detachable_iqn_list_validator, @@ -353,9 +448,9 @@ def def_destroy_parser(s_parser): ArgumentParser: the destroy subcommand parser """ destroy_parser = s_parser.add_parser('destroy', - description='Destroy a block volume.', - help='Destroy a block volume.' - ) + description='Destroy a block volume.', + help='Destroy a block volume.' + ) destroy_parser.add_argument('-O', '--ocids', required=True, type=volume_oci_list_validator, @@ -378,230 +473,96 @@ def def_destroy_parser(s_parser): return destroy_parser -def get_args_parser(): +def _getch(): """ - Parse the command line arguments and return an object representing the - command line (as returned by argparse's parse_args()). + Read a single keypress from stdin. Returns ------- - The commandline argparse namespace. + The resulting character. """ - parser = argparse.ArgumentParser(prog='oci-iscsi-config', - description='Utility for listing or configuring iSCSI devices on an OCI instance.' - ) - subparser = parser.add_subparsers(dest='command') - # - # usage - _ = def_usage_parser(subparser) - # - # sync - _ = def_sync_parser(subparser) - # - # show-all - _ = def_show_all_parser(subparser) - # - # show - _ = def_show_parser(subparser) - # - # create - _ = def_create_parser(subparser) - # - # attach - _ = def_attach_parser(subparser) - # - # detach - _ = def_detach_parser(subparser) - # - # destroy - _ = def_destroy_parser(subparser) - - return parser + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(fd) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch -def volume_size_validator(value): +def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): """ - Validate than value passed is an int and greater than 50 (GB). + Read yes or no form stdin, No being the default. Parameters ---------- - value: str - Size in GB. - + prompt: str + The message. + yn: bool + Add (y/N) to the prompt if True. + waitenter: bool + Wait for the enter key pressed if True, proceed immediately + otherwise. + suppose_yes: bool + if True, consider the answer is yes. + default_yn: bool + The default answer. Returns ------- - int: size in GB on success. + bool: True on yes, False otherwise. """ - _logger.debug('%s', where_am_i()) - _i_value = 0 - try: - _i_value = int(value) - except ValueError as e: - raise argparse.ArgumentTypeError("Block volume size must be a int") from e + yn_prompt = prompt + ' ' + # + # if yes is supposed, write prompt and return True. + if suppose_yes: + _ = sys.stdout.write(yn_prompt) + sys.stdout.flush() + return True + # + # add y/N to prompt if necessary. + if yn: + if default_yn: + yn_prompt += ' (Y/n)' + yn = 'Y' + else: + yn_prompt += ' (y/N) ' + yn = 'N' + # + # if wait is set, wait for return key. + if waitenter: + resp_len = 0 + while resp_len == 0: + resp = input(yn_prompt).lstrip() + resp_len = len(resp) + yn_i = list(resp)[0].rstrip() + # + # if wait is not set, proceed on any key pressed. + else: + _ = sys.stdout.write(yn_prompt) + sys.stdout.flush() + yn_i = _getch().rstrip() - if _i_value < 50: - raise argparse.ArgumentTypeError("Volume size must be at least 50GBs") - return _i_value + sys.stdout.write('\n') + if bool(yn_i): + yn = yn_i + return bool(yn.upper() == 'Y') -def attachable_iqn_list_validator(value): +def ask_yes_no(question): """ - Validate that value passed is a list of iqn and/or ocid. + Ask the user a question and enforce a yes/no answer. Parameters ---------- - value: str - A comma separated list of iqn's. - - Returns - ------- - list: a list of iqn's. - """ - _logger.debug('%s', where_am_i()) - _iqns = [iqn.strip() for iqn in value.split(',') if iqn] - for iqn in _iqns: - if not iqn.startswith(iqn_tag) and not iqn.startswith(oci_volume_tag): - raise argparse.ArgumentTypeError('Invalid IQN %s' % iqn) - return _iqns - - -def detachable_iqn_list_validator(value): - """ - Validate the value passed is a list of iqn and does not contain boot volume. - - Parameters - ---------- - value: str - A comma separated list of iqn's. - - Returns - ------- - list: a list of iqn's. - """ - _logger.debug('%s', where_am_i()) - _iqns = [iqn.strip() for iqn in value.split(',') if iqn] - for iqn in _iqns: - if not iqn.startswith(iqn_tag): - raise argparse.ArgumentTypeError('Invalid IQN %s' % iqn) - if 'boot:uefi' in iqn: - raise argparse.ArgumentTypeError('Cannot detach boot volume IQN %s' % iqn) - return _iqns - - -def volume_oci_list_validator(value): - """ - Validate than value passed is a list of volume ocid's. - - Parameters - ---------- - value: str - A comma separated list of ocid's. - - Returns - ------- - list: a list of ocid's - """ - _logger.debug('%s', where_am_i()) - _ocids = [ocid.strip() for ocid in value.split(',') if ocid] - for ocid in _ocids: - if not ocid.startswith(oci_volume_tag): - raise argparse.ArgumentTypeError('Invalid volume OCID %s' % ocid) - return _ocids - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - _logger.debug('%s', where_am_i()) - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - _logger.debug('%s', where_am_i()) - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def ask_yes_no(question): - """ - Ask the user a question and enforce a yes/no answer. - - Parameters - ---------- - question : str - The question. + question : str + The question. Returns ------- bool True for yes, False for no. """ - _logger.debug('%s', where_am_i()) while True: print(question) ans = input().lower() @@ -627,7 +588,6 @@ def compat_info_message(compat_msg=None, gen_msg=None, mode='gen'): ------- No return value. """ - _logger.debug('%s', where_am_i()) if bool(compat_msg): if mode == 'compat': _logger.info(compat_msg) @@ -636,124 +596,236 @@ def compat_info_message(compat_msg=None, gen_msg=None, mode='gen'): _logger.info(gen_msg) -def show_usage(usage_args): - """ - Wrapper for showing usage info. - - Parameters - ---------- - usage_args: - The command line arguments. - - Returns - ------- - bool: True on success, False otherwise. - """ - _logger.debug('%s', where_am_i()) - return True - - -def get_iscsiadm_session(): +def get_instance_ocid(): """ - Find the attached block volumes, except the boot volume. + Gets the instance OCID; fetch in the instance InstanceMetadata the + ID of the current instance Returns ------- - dict: the attached block volumes and their data. + str + The instance id or '' if not found. """ - _logger.debug('%s', where_am_i()) - all_volumes = iscsiadm.session() - iscsiadmsession = dict((iqn, all_volumes[iqn]) for iqn in all_volumes if 'boot:uefi' not in iqn) - return iscsiadmsession + return InstanceMetadata().refresh()['instance']['id'] -def get_columns(details, mode, column_lengths): +def ocid_refresh(wait=False): """ - Set the column lenghts. + Refresh OCID cached information; it runs + /usr/libexec/ocid command line with --refresh option Parameters ---------- - details: bool - If True, include the 'details' - mode: str - The output mode. - column_lengths: list - The column lengths. + wait: bool + Flag, wait until completion if set. Returns ------- - list: the columns lenghts. + bool + True on success, False otherwise. """ - _logger.debug('%s', where_am_i()) - columns = list() - if details: - columns.append(['Target', column_lengths['target']+2, 'target']) - columns.append(['Volume Name', column_lengths['name']+2, 'name']) - if details: - columns.append(['Volume OCID', column_lengths['ocid']+2, 'ocid']) - columns.append(['Persistent Portal', column_lengths['p_portal']+2, 'p_portal']) - columns.append(['Current Portal', column_lengths['c_portal']+2, 'c_portal']) - columns.append(['Session State', column_lengths['s_state']+2, 's_state']) - columns.append(['Attached Device', column_lengths['dev']+2, 'dev']) - columns.append(['Size', column_lengths['size']+2, 'size']) - if details or mode in ['text', 'parsable']: - columns.append(['Mountpoint', column_lengths['mountpoint']+2, 'mountpoint']) - columns.append(['Filesystem', column_lengths['fstype']+2, 'fstype']) - return columns + _cmd = ['/usr/libexec/ocid', '--refresh', 'iscsi'] + if wait: + _cmd.append('--no-daemon') + try: + _logger.debug('Executing %s', _cmd) + output = subprocess.check_output(_cmd, stderr=subprocess.STDOUT).decode('utf-8').splitlines() + if _logger.isEnabledFor(logging.DEBUG): + _logger.debug('Ocid run output: %s', str(output)) + return True + except subprocess.CalledProcessError as e: + _logger.debug('Launch of ocid failed : %s', str(e)) + return False -def get_volume_by_iqn(sess, iqn): +def _display_oci_volume_list(volumes, output_mode, details, truncate): """ - Gets a volume by given IQN + Display information about list of block volumes. Parameters ---------- - sess: OCISession - The OCISEssion instance. - iqn: str - The iSCSI qualified name. - - Returns - ------- - OCIVolume : the found volume or None + volumes: list + List of OCIVOlumes + output_mode: str + Output mode + details: bool + Display details information if True + truncate: bool + Truncate text if False """ - _logger.debug('%s: %s', where_am_i(), iqn) - try: - if bool(sess): - get_volume_by_iqn.all_this_instance_volume = sess.this_instance().all_volumes() - for volume in get_volume_by_iqn.all_this_instance_volume: - if volume.get_iqn() == iqn: - _logger.debug('Found %s', str(volume)) - return volume - else: - _logger.info('Unable to get volume ocid and display name for iqn [%s], ', iqn) - except Exception as e: - _logger.debug('Failed to get volume data for iqn [%s]: %s', iqn, str(e), stack_info=True, exc_info=True) - _logger.error('Failed to get volume data for iqn [%s]', iqn) - return None + def _get_displayable_size(_, volume): + return volume.get_size(format_str=OCI_VOLUME_SIZE_FMT.HUMAN.name) -def collect_volumes_data(oci_session, iscsi_session, disks, col_lengths): - """ - Collect data from volumes with respect to display. + def _get_attached_instance_name(_, volume): + """ - Parameters - ---------- - oci_session: OCISession - An oci api session. - iscsi_session: list - The list of iscsi devices. - disks: dict - Volume and partition data. - col_lengths: list - The max lengths of the volume paramter values and the headers. + Parameters + ---------- + _ + volume - Returns - ------- - tuple: (dict, list) - (The volume data, The max lenghts) - """ - volumes_data = list() + Returns + ------- + + """ + global _this_instance_ocid + if not volume.is_attached(): + return '-' + _vol_instance_attach_to = volume.get_instance() + if _vol_instance_attach_to.get_ocid() == _this_instance_ocid: + return "this instance" + pip = _vol_instance_attach_to.get_public_ip() + if pip: + return "%s (%s)" % (_vol_instance_attach_to.get_display_name(), _vol_instance_attach_to.get_public_ip()) + return _vol_instance_attach_to.get_display_name() + + def _get_comp_name(_, volume): + """ keep track of compartment per ID as it may be expensive info to fetch """ + _map = getattr(_get_comp_name, 'c_id_to_name', {}) + if volume.get_compartment_id() not in _map: + _map[volume.get_compartment_id()] = volume.get_compartment().get_display_name() + setattr(_get_comp_name, 'c_id_to_name', _map) + return _map[volume.get_compartment_id()] + + def _get_vol_data_iqn(_, volume): + iqn = volume.get_iqn() + return iqn if iqn is not None else '-' + + if len(volumes) == 0: + print('No other volumes found.') + else: + _collen = {'name': len('Name'), + 'size': len('Size'), + 'attachedto': len('Attached to'), + 'ocid': len('OCID'), + 'iqn': len('IQN'), + 'compartment': len('Compartment'), + 'availdomain': len('Availability Domain')} + volumes_data = list() + for vol in volumes: + _vol_data = dict() + # name + _vol_data['name'] = vol.get_display_name() + _vol_name_len = len(_vol_data['name']) + _collen['name'] = max(_vol_name_len, _collen['name']) + # size + _vol_data['size'] = vol.get_size(OCI_VOLUME_SIZE_FMT.HUMAN.name) + _vol_size_len = len(_vol_data['size']) + 1 + _collen['size'] = max(_vol_size_len, _collen['size']) + # attached to + _vol_data['attachedto'] = _get_attached_instance_name(None, vol) + _vol_attachedto_len = len(_vol_data['attachedto']) + _collen['attachedto'] = max(_vol_attachedto_len, _collen['attachedto']) + # ocid + _vol_data['ocid'] = vol.get_ocid() + _vol_ocid_len = len(_vol_data['ocid']) + _collen['ocid'] = max(_vol_ocid_len, _collen['ocid']) + if details: + # iqn + _vol_data['iqn'] = _get_vol_data_iqn(None, vol) + _vol_iqn_len = len(_vol_data['iqn']) + _collen['iqn'] = max(_vol_iqn_len, _collen['iqn']) + # compartment + _vol_data['compartment'] = _get_comp_name(None, vol) + _vol_compartment_len = len(_vol_data['compartment']) + _collen['compartment'] = max(_vol_compartment_len, _collen['compartment']) + # availability domain + _vol_data['availdomain'] = vol.get_availability_domain_name() + _vol_availdomain_len = len(_vol_data['availdomain']) + _collen['availdomain'] = max(_vol_availdomain_len, _collen['availdomain']) + volumes_data.append(_vol_data) + + _title = 'Block volumes information:' + _columns = list() + if truncate: + _collen['name'] = 32 + _collen['size'] = 6 + _collen['attachedto'] = 32 + _collen['ocid'] = 32 + if details: + _collen['iqn'] = 14 + _collen['compartment'] = 14 + _collen['availdomain'] = 19 + + _columns.append(['Name', _collen['name']+2, 'name']) + _columns.append(['Size', _collen['size']+2, 'size']) + _columns.append(['Attached to', _collen['attachedto']+2, 'attachedto']) + _columns.append(['OCID', _collen['ocid']+2, 'ocid']) + if details: + _columns.append(['IQN', _collen['iqn']+2, 'iqn']) + _columns.append(['Compartment', _collen['compartment']+2, 'compartment']) + _columns.append(['Availability Domain', _collen['availdomain']+2, 'availdomain']) + + if output_mode == 'compat': + printerKlass = get_row_printer_impl('text') + else: + printerKlass = get_row_printer_impl(output_mode) + + printer = printerKlass(title=_title, columns=_columns, text_truncate=truncate) + printer.printHeader() + # for vol in volumes: + for vol in volumes_data: + printer.printRow(vol) + printer.rowBreak() + printer.printFooter() + printer.finish() + + +def get_oci_api_session(): + """ + Ensure the OCI SDK is available if the option is not None. + + Returns + ------- + OCISession + The session or None if we cannot get one + """ + session_cache = getattr(get_oci_api_session, "_session", None) + if session_cache: + return session_cache + + sess = None + + try: + _logger.debug('Creating session') + sess = oci_utils.oci_api.OCISession() + # it seems that having a client is not enough, we may not be able to query anything on it. + # workaround: + # try a dummy call to be sure that we can use this session + if not bool(sess.this_instance()): + _logger.debug('Returning None session') + return None + setattr(get_oci_api_session, "_session", sess) + except Exception as e: + _logger.error("Failed to access OCI services: %s", str(e)) + _logger.error("Unable to authenticate correctly. Verify the Instance Principals " + "or Direct Authentication configuration.") + _logger.debug('Returning session') + return sess + + +def collect_volumes_data(oci_session, iscsi_session, disks, col_lengths): + """ + Collect data from volumes with respect to display. + + Parameters + ---------- + oci_session: OCISession + An oci api session. + iscsi_session: list + The list of iscsi devices. + disks: dict + Volume and partition data. + col_lengths: list + The max lengths of the volume paramter values and the headers. + + Returns + ------- + tuple: (dict, list) + (The volume data, The max lenghts) + """ + volumes_data = list() for iqn in list(iscsi_session.keys()): # _item = {} _vol_data = dict() @@ -805,152 +877,41 @@ def collect_volumes_data(oci_session, iscsi_session, disks, col_lengths): return volumes_data, col_lengths -def _display_oci_volume_list(volumes, args): +def get_columns(details, mode, column_lengths): """ - Display information about list of block volumes. + Set the column lenghts. Parameters ---------- - volumes: list - List of OCIVOlumes - args: namespace - the command line - """ - - def _get_displayable_size(_, volume): - """ - Get the volume sizes. - - Parameters - ---------- - _ - volume: OCIVolume - volume object - - Returns - ------- - str: the volume size. - """ - return volume.get_size(format_str=OCI_VOLUME_SIZE_FMT.HUMAN.name) - - def _get_attached_instance_name(_, volume): - """ - Get the instance name the volume is attached to. - - Parameters - ---------- - _ - volume: OCIVolume - volume object - - Returns - ------- - str: instance display name - """ - global _this_instance_ocid - if not volume.is_attached(): - return '-' - _vol_instance_attach_to = volume.get_instance() - - if _vol_instance_attach_to.get_ocid() == _this_instance_ocid: - return "this instance" - pip = _vol_instance_attach_to.get_public_ip() - if pip: - return "%s (%s)" % (_vol_instance_attach_to.get_display_name(), _vol_instance_attach_to.get_public_ip()) - return _vol_instance_attach_to.get_display_name() - - def _get_comp_name(_, volume): - """ - Get the compartment name. - - Parameters - ---------- - _ - volume: OCIVolume - volume object - - Returns - ------- - str: the compartment name - """ - _map = getattr(_get_comp_name, 'c_id_to_name', {}) - if volume.get_compartment_id() not in _map: - _map[volume.get_compartment_id()] = volume.get_compartment().get_display_name() - setattr(_get_comp_name, 'c_id_to_name', _map) - return _map[volume.get_compartment_id()] - - def _get_vol_data_iqn(_, volume): - """ - Get the iqn of the volume. - - Parameters - ---------- - _ - volume: OCIVolume - volume object - - Returns - ------- - str: the iqn of the volume. - """ - iqn = volume.get_iqn() - return iqn if iqn is not None else '-' - - _logger.debug('%s', where_am_i()) - - _data_struct = { - 'name': {'head': 'Name', 'func': 'get_display_name', 'type': 'str', 'collen': 8}, - 'size': {'head': 'Size', 'func': 'get_size', 'type': 'str', 'collen': 6}, - 'attachedto': {'head': 'Attached to', 'attrib': 'attachedto', 'type': 'str', 'collen': 15}, - 'ocid': {'head': 'OCID', 'func': 'get_ocid', 'type': 'str', 'collen': 32}, - } - _data_struct_detail = { - 'iqn': {'head': 'iqn', 'func': 'get_iqn', 'type': 'str', 'collen': 32}, - 'compartment': {'head': 'Compartment', 'func': ['get_compartment', 'get_display_name'], 'type': 'str', 'collen': 14}, - 'availdomain': {'head': 'Availability Domain', 'func': 'get_availability_domain_name', 'type': 'str', 'collen': 19}, - } - # - # add details information - if args.details: - _data_struct.update(_data_struct_detail) - # - # initialise the column widths if no-truncate is set - if args.no_truncate: - _data_struct = initialise_column_lengths(_data_struct) - - if len(volumes) == 0: - print('No other volumes found.') - else: - volumes_data = list() - for vol in volumes: - vol.attachedto = _get_attached_instance_name(None, vol) - vol.compartment = _get_comp_name(None, vol) - vol.iqn = _get_vol_data_iqn(None, vol) - - _vol_data = dict() - for key, _ in _data_struct.items(): - value_data = get_value_data(vol, _data_struct[key]) - _vol_data[key] = value_data[0] - val_length = value_data[1] - if args.no_truncate: - _data_struct[key]['collen'] = max(val_length, _data_struct[key]['collen']) - volumes_data.append(_vol_data) - - _title = 'Block volumes information:' - - if args.output_mode == 'compat': - title = 'Other available storage volumes:' - else: - title = 'Other available storage volumes' - print_data(title, - _data_struct, volumes_data, - mode=args.output_mode, - truncate=not args.no_truncate) + details: bool + If True, include the 'details' + mode: str + The output mode. + column_lengths: list + The column lengths. - return True + Returns + ------- + list: the columns lenghts. + """ + columns = list() + if details: + columns.append(['Target', column_lengths['target']+2, 'target']) + columns.append(['Volume Name', column_lengths['name']+2, 'name']) + if details: + columns.append(['Volume OCID', column_lengths['ocid']+2, 'ocid']) + columns.append(['Persistent Portal', column_lengths['p_portal']+2, 'p_portal']) + columns.append(['Current Portal', column_lengths['c_portal']+2, 'c_portal']) + columns.append(['Session State', column_lengths['s_state']+2, 's_state']) + columns.append(['Attached Device', column_lengths['dev']+2, 'dev']) + columns.append(['Size', column_lengths['size']+2, 'size']) + if details or mode in ['text', 'parsable']: + columns.append(['Mountpoint', column_lengths['mountpoint']+2, 'mountpoint']) + columns.append(['Filesystem', column_lengths['fstype']+2, 'fstype']) + return columns -def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): +def display_attached_volumes(oci_sess, iscsiadm_session, disks, output_mode, details, truncate): """ Display the attached iSCSI devices. @@ -963,8 +924,9 @@ def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): disks: dict List of disk to be displayed. Information about disks in the system, as returned by lsblk.list_blk_dev() - args: nomespace - The command line arguments. + output_mode : the output mode as str (text,json,parsable) + details : display detailed information ? + truncate: truncate text? Returns ------- @@ -985,7 +947,7 @@ def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): print("Local iSCSI info not available.") print("List info from Cloud instead(No boot volume).") print("") - _display_oci_volume_list(oci_vols, args) + _display_oci_volume_list(oci_vols, output_mode, details, truncate) return _cols = ['Target', @@ -1014,7 +976,7 @@ def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): volumes_data, _collen = collect_volumes_data(oci_sess, iscsiadm_session, disks, dict(zip(_col_name, _cols_len))) - if not args.no_truncate: + if truncate: _collen = {'target': 32, 'name': 13, 'ocid': 32, @@ -1026,28 +988,28 @@ def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): 'mountpoint': 12, 'fstype': 12} - _columns = get_columns(args.details, args.output_mode, _collen) + _columns = get_columns(details, output_mode, _collen) # this is only to be used in compatibility mode, text mode or parsable mode, for now. - partitionPrinter = get_row_printer_impl(args.output_mode)(title='\nPartitions:\n', - columns=(['Device', 8, 'dev_name'], - ['Size', 6, 'size'], - ['Filesystem', 12, 'fstype'], - ['Mountpoint', 12, 'mountpoint'])) + partitionPrinter = get_row_printer_impl(output_mode)(title='\nPartitions:\n', + columns=(['Device', 8, 'dev_name'], + ['Size', 6, 'size'], + ['Filesystem', 12, 'fstype'], + ['Mountpoint', 12, 'mountpoint'])) iscsi_dev_printer = None if len(volumes_data) == 0: print('No iSCSI devices attached.') else: _title = 'Currently attached iSCSI devices:' - iscsi_dev_printer = get_row_printer_impl(args.output_mode)(title=_title, - columns=_columns, - text_truncate=args.no_truncate) + iscsi_dev_printer = get_row_printer_impl(output_mode)(title=_title, + columns=_columns, + text_truncate=truncate) if bool(iscsi_dev_printer): iscsi_dev_printer.printHeader() for _item in volumes_data: iscsi_dev_printer.printRow(_item) - if args.output_mode in ['compat', 'text', 'parsable']: + if output_mode in ['compat', 'text', 'parsable']: if 'partitions' not in disks[_item['dev']]: # fstype = disks[_item['dev']]['fstype'] \ @@ -1067,7 +1029,7 @@ def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): partitionPrinter.printRow(partitions[part]) partitionPrinter.rowBreak() partitionPrinter.printFooter() - if not args.output_mode == 'parsable': + if not output_mode == 'parsable': partitionPrinter.finish() iscsi_dev_printer.rowBreak() iscsi_dev_printer.printFooter() @@ -1075,278 +1037,51 @@ def display_attached_volumes(oci_sess, iscsiadm_session, disks, args): return -def api_display_available_block_volumes(sess, args): +# def display_detached_iscsi_device(iqn, targets, attach_failed=()): +# """ +# Display the iSCSI devices +# +# Parameters +# ---------- +# iqn: str +# The iSCSI qualified name. +# targets: dict +# The targets. +# attach_failed: dict +# The devices for which attachment failed. +# """ +# devicePrinter = get_row_printer_impl('table')(title="Target %s" % iqn, +# text_truncate=False, +# columns=(['Portal', 20, 'portal'], ['State', 65, 'state'])) +# devicePrinter.printHeader() +# _item = {} +# for ipaddr in list(targets.keys()): +# _item['portal'] = "%s:3260" % ipaddr +# if iqn in attach_failed: +# _item['state'] = iscsiadm.error_message_from_code(attach_failed[iqn]) +# else: +# _item['state'] = "Detached" +# devicePrinter.printRow(_item) +# devicePrinter.rowBreak() +# devicePrinter.printFooter() +# devicePrinter.finish() + +def get_volume_data_from_(somekey, sess): """ - Display the available devices for the compartments specified. + Collect the data of an iscsi volume based on the iqn, the ocid or the display name. Parameters ---------- + somekey: str + The iSCSI qualified name, the ocid or the display name. sess: OCISession - The OCISession instance. - args: namespace - The command line. + An oci sdk session. Returns ------- - No return value. + dict: The volume data if exist and is unique, False otherwise """ - _logger.debug('%s', where_am_i()) - _title = "Other available storage volumes:" - if sess is None: - _logger.info("Failed to create session, unable to show available volumes.") - return - - vols = [] - compartments = args.compartments - if len(compartments) > 0: - # - # -C/--compartment option used - for cspec in compartments: - try: - if cspec == 'all': - vols = sess.all_volumes() - break - if cspec.startswith('ocid1.compartment.oc1..'): - # compartment specified with its ocid - comp = sess.get_compartment(ocid=cspec) - if comp is None: - _logger.error("Compartment not found: %s", cspec) - else: - cvols = comp.all_volumes() - vols += cvols - else: - # compartment specified with display name regexp - comps = sess.find_compartments(display_name=cspec) - if len(comps) == 0: - _logger.error("No compartments matching '%s' found", cspec) - else: - for comp in comps: - cvols = comp.all_volumes() - vols += cvols - except Exception as e: - _logger.error('Failed to get data for compartment %s: %s', cspec, str(e)) - else: - # - # -C/--compartment option wasn't used, default to the instance's own - # compartment - try: - comp = sess.this_compartment() - avail_domain = sess.this_availability_domain() - if comp is not None: - vols = comp.all_volumes(availability_domain=avail_domain) - _title = "Other available storage volumes %s/%s:" % (comp.get_display_name(), avail_domain) - else: - _logger.error("Compartment for this instance not found") - except Exception as e: - _logger.error('Failed to get data for this compartment: %s', str(e)) - - if len(vols) == 0: - _logger.info("No additional storage volumes found.") - return - - _vols_to_be_displayed = [] - for v in vols: - if v.is_attached() and not args.all: - continue - # display also the attached ones - _vols_to_be_displayed.append(v) - _vols_to_be_displayed.sort() - _display_oci_volume_list(_vols_to_be_displayed, args) - - -def show_volumes(oci_session, iscsiadm_session, system_disks, args): - """ - Show iscsi volumes. - - Parameters - ---------- - oci_session: OCISession - The oci session. - iscsiadm_session: dict - The iscsiadm session. - system_disks: dict - The attached volumes. - args: namespace - The command line arguments. - - Returns - ------- - bool: True - """ - _logger.debug('%s', where_am_i()) - # - # set the compatibility parameters, if necessary - compatibility_mode, args.output_mode, args.details = get_compatibility_mode(args) - - display_attached_volumes(oci_session, - iscsiadm_session, - system_disks, - args) - if len(args.compartments) > 0 or args.all: - api_display_available_block_volumes(oci_session, args) - - return True - - -def get_instance_ocid(): - """ - Gets the instance OCID; fetch in the instance InstanceMetadata the - ID of the current instance - - Returns - ------- - str - The instance id or '' if not found. - """ - return InstanceMetadata().refresh()['instance']['id'] - - -def get_this_instance_ocid(session): - """ - Get the ocid of the current instance, via the api or via the metadata. - - Parameters - ---------- - session: OCISession - The oci session. - - Returns - ------- - str: the ocid - """ - _logger.debug('%s', where_am_i()) - if bool(session): - if bool(session.this_instance()): - return session.this_instance().get_ocid() - _logger.error('Failed to retrieve instance information.') - sys.exit(1) - else: - return get_instance_ocid() - - -def do_show(args): - """ - Show iscsi block volumes. - - Parameters - ---------- - args: namespace - The commandline. - - Returns - ------- - bool: True on success, False otherwise. - """ - global _this_instance_ocid - # - _logger.debug('%s', where_am_i()) - # create an oci api session - oci_sess = get_oci_api_session() - # collect iscsi volume information - system_disks = lsblk.list_blk_dev() - # we are not touching boot volume in iscsi config - iscsiadm_session = iscsiadm.session() - # get the ocid of this instance - _this_instance_ocid = get_this_instance_ocid(session=oci_sess) - - try: - _ = show_volumes(oci_session=oci_sess, - iscsiadm_session=iscsiadm_session, - system_disks=system_disks, - args=args) - except Exception as e: - _logger.debug('Failed to show block volumes: %s', str(e), stack_info=True) - return False - return True - - -def do_show_all(args): - """ - Show all iscsi block volumes. - - Parameters - ---------- - args: namespace - The commandline. - - Returns - ------- - bool: True on success, False otherwise. - """ - _logger.debug('%s', where_am_i()) - args.all = True - # args.output_mode = 'table' - args.no_truncate = not args.truncate - args.compartments = () - args.details = True - return do_show(args) - - -def get_oci_api_session(): - """ - Ensure the OCI SDK is available if the option is not None. - - Returns - ------- - OCISession - The session or None if we cannot get one - """ - _logger.debug('%s', where_am_i()) - session_cache = getattr(get_oci_api_session, "_session", None) - if session_cache: - return session_cache - - sess = None - - try: - _logger.debug('Creating session') - sess = oci_utils.oci_api.OCISession() - # it seems that having a client is not enough, we may not be able to query anything on it. - # workaround: - # try a dummy call to be sure that we can use this session - if not bool(sess.this_instance()): - _logger.debug('Returning None session') - return None - setattr(get_oci_api_session, "_session", sess) - except Exception as e: - _logger.error("Failed to access OCI services: %s", str(e)) - _logger.error("Unable to authenticate correctly. Verify the Instance Principals " - "or Direct Authentication configuration.") - _logger.debug('Returning session') - return sess - -def display_iscsi_device(vol): - """ - Print the data for iscsi device identified by iqn. - Parameters - ---------- - vol: list - The volume data. - - Returns - ------- - bool: True on success, False otherwise. - """ - print('%s %s %s:%s [%s]' % (vol['name'], vol['iqn'], vol['portal_ip'], vol['portal_port'], vol['ocid'])) - return True - - -def get_volume_data_from_(somekey, sess): - """ - Collect the data of an iscsi volume based on the iqn, the ocid or the display name. - - Parameters - ---------- - somekey: str - The iSCSI qualified name, the ocid or the display name. - sess: OCISession - An oci sdk session. - - Returns - ------- - dict: The volume data if exist and is unique, False otherwise - """ - _logger.debug('%s: %s', where_am_i(), somekey) + _logger.debug('_get volume data for %s', somekey) this_compartment = sess.this_compartment() this_availability_domain = sess.this_availability_domain() all_volumes = this_compartment.all_volumes(this_availability_domain) @@ -1412,361 +1147,433 @@ def get_volume_data_from_(somekey, sess): return those_vols[0] -def sync_detached_devices(oci_session, detached_volumes, targets, apply=False, interactive=False, apply_yes=False): +def display_iscsi_device(vol): """ - Try to attach volumes in the detached volumes list. + Print the data for iscsi device identified by iqn. + Parameters + ---------- + vol: list + The volume data. + + Returns + ------- + bool: True on success, False otherwise. + """ + print('%s %s %s:%s [%s]' % (vol['name'], vol['iqn'], vol['portal_ip'], vol['portal_port'], vol['ocid'])) + return True + + +def _do_iscsiadm_attach(iqn, targets, user=None, passwd=None, iscsi_portal_ip=None): + """ + Attach an iSCSI device. Parameters ---------- - oci_session: OCISession - The oci api session. - detached_volumes: list - The iqn's of the detached volumes. + iqn: str + The iSCSI qualified name. targets: dict - The targets. - apply: bool - Try to attach if True. - interactive: bool - Compatiblity flag, Try to attach if True. - apply_yes: bool - Assume yes if True. - + The targets, + user: str + The iscsiadm username. + passwd: str + The iscsiadm user password. + iscsi_portal_ip: str + portal IP Returns ------- - tuple: (bool, int) - Something changed/[0,1] + None + Raise + ----- + Exception in case of error """ - _logger.debug('%s', where_am_i()) - did_something = False - retval = 0 - for iqn in detached_volumes: - # display_detached_iscsi_device(iqn, targets) - this_volume_data = get_volume_data_from_(iqn, oci_session) - if not this_volume_data: - _logger.error('Volume with iqn %s does not exist.', iqn) - # if invalid iqn in detached volume list, clean up - if apply or interactive: - if apply_yes: - ans = True - else: - ans = _read_yn('Would you like to remove %s from detached volume list?' % iqn, - yn=True, - waitenter=True, - suppose_yes=False, - default_yn=False) - if ans: - detached_volumes.remove(iqn) - write_cache_11876(cache_content=list(set(detached_volumes)), - cache_fname=iscsiadm.IGNOREIQNS_CACHE, - cache_fname_11876=__ignore_file) - else: - _ = display_iscsi_device(this_volume_data) - if apply or interactive: - if apply_yes: - ans = True - else: - ans = _read_yn('Would you like to attach this device?', - yn=True, - waitenter=True, - suppose_yes=False, - default_yn=False) - if ans: - try: - chap = True if this_volume_data['chap_user'] is not None else False - attach_data = do_oci_vol_attach_ocid(oci_session, 'gen', this_volume_data['ocid'], chap) - # _do_iscsiadm_attach(this_volume_data['iqn'], - # targets, - # user=this_volume_data['chap_user'], - # passwd=this_volume_data['chap_pw'], - # iscsi_portal_ip=this_volume_data['portal_ip']) - detached_volumes.remove(this_volume_data['iqn']) - write_cache_11876(cache_content=list(set(detached_volumes)), - cache_fname=iscsiadm.IGNOREIQNS_CACHE, - cache_fname_11876=__ignore_file) - did_something = True - except Exception as e: - _logger.error('[%s] attachment failed: %s', iqn, str(e)) - retval = 1 - return did_something, retval + if not iscsi_portal_ip: + portal_ip = None + if targets is None: + raise Exception("Ocid service must be running to determine the portal IP address for this device.") + for ipaddr in list(targets.keys()): + if iqn in targets[ipaddr]: + portal_ip = ipaddr + if portal_ip is None: + # + # this shouldn't really happen, but just in case + raise Exception("Can't find portal IP address") + else: + portal_ip = iscsi_portal_ip -def get_chap_secret(iqn): + _logger.debug('Portal: ip %s; iqn: %s; user %s; passwd: %s', portal_ip, iqn, user, passwd) + retval = iscsiadm.attach(portal_ip, 3260, iqn, user, passwd, auto_startup=True) + + if retval != 0: + _logger.info("Result: %s", iscsiadm.error_message_from_code(retval)) + raise Exception('iSCSI attachment failed: %s' % iscsiadm.error_message_from_code(retval)) + + +def do_detach_volume(oci_session, iscsiadm_session, iqn, mode): """ - Look for a saved (user,password) pair for iqn in the chap secrets file. + Detach the volume with given IQN Parameters ---------- + oci_session: OCISession + The oci session. + iscsiadm_session: + iscsiadm session iqn: str - The iSCSI qualified name. + The IQN. + mode: str + Show output in 0.11 compatibility mode is set to 'compat' Returns ------- - tuple - The (timestamp, password) on success, (None,None) otherwise. - + None + Raise + ----- + Exception : when destroy has failed """ - # _, chap_passwords = load_cache(__chap_password_file) - _logger.debug('%s', where_am_i()) - _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, - global_file_11876=__chap_password_file) - if chap_passwords is None: - return None, None - if iqn in chap_passwords: - return chap_passwords[iqn] - return None, None + _volume = get_volume_by_iqn(oci_session, iqn) + if _volume is None: + raise Exception("Volume with IQN [%s] not found" % iqn) + try: + compat_info_message(compat_msg="Detaching volume", + gen_msg="Detaching volume %s [%s]" % (_volume.get_display_name(), + _volume.get_iqn()), mode=mode) + _volume.detach() + except Exception as e: + _logger.debug("Failed to disconnect volume", exc_info=True) + _logger.error('%s', str(e)) + raise Exception("Failed to disconnect volume %s" % iqn) from e -def sync_failed_attached(oci_session, failed_volumes, targets, apply=False, interactive=False, apply_yes=False): + _logger.debug('Volume detached, detaching it from iSCSI session') + if not iscsiadm.detach(iscsiadm_session[iqn]['persistent_portal_ip'], + iscsiadm_session[iqn]['persistent_portal_port'], + iqn): + raise Exception("Failed to detach target %s" % iqn) + + +def do_destroy_volume(sess, ocid): """ - Try to attach volumes in the failed attached volumes list. + Destroy the volume with the given ocid. + The volume must be detached. This is just an added measure to + prevent accidentally destroying the wrong volume. + + Add root privilege requirement to be the same as create_volumerequirement. + Parameters ---------- - oci_session: OCISession - The oci api session. - failed_volumes: list - The iqn's of volumes failed attachment. - targets: list - The targets. - apply: bool - Try to attach if True. - interactive: bool - Compatiblity flag, Try to attach if True. - apply_yes: bool - Assume yes if True. + sess: OCISession + The OCI service session. + ocid: str + The OCID. Returns ------- - tuple: (bool, int) - Something changed/[0,1] + None + Raise + ----- + Exception : when destroy has failed """ - _logger.debug('%s', where_am_i()) - did_something = False - retval = 0 - for iqn in list(failed_volumes.keys()): - # display_detached_iscsi_device(iqn, targets, attach_failed) - this_volume_data = get_volume_data_from_(iqn, oci_session) - if this_volume_data: - _ = display_iscsi_device(this_volume_data) - _attach_user_name = None - _attach_user_passwd = None - _give_it_a_try = False - if apply or interactive: - if failed_volumes[iqn] != 24: - # not authentication error - # if args.yes or ask_yes_no("Would you like to retry attaching this device?"): - if _read_yn('Would you like to retry attaching this device?', - yn=True, - waitenter=True, - suppose_yes=False, - default_yn=False): - _give_it_a_try = True - else: - _logger.debug('%s in failed list because of authorisation failure.', iqn) - # authentication error - # if args.yes or ask_yes_no("Would you like to configure this device?"): - if apply_yes or _read_yn('Would you like to configure this device?', - yn=True, - waitenter=True, - suppose_yes=False, - default_yn=False): - _give_it_a_try = True - if oci_session is not None: - this_volume_data = get_volume_data_from_(iqn, oci_session) - _attach_user_name = this_volume_data['chap_user'] - _attach_user_passwd = this_volume_data['chap_pw'] - else: - (_attach_user_name, _attach_user_passwd) = get_chap_secret(iqn) - if _attach_user_name is None: - _logger.error('Cannot retreive chap credentials') - _give_it_a_try = False - if _give_it_a_try: - try: - chap = True if this_volume_data['chap_user'] is not None else False - attach_data = do_oci_vol_attach_ocid(oci_session, 'gen', this_volume_data['ocid'], chap) - failed_volumes = {key:failed_volumes[key] - for key in failed_volumes if key != this_volume_data['iqn']} - write_cache(cache_content=[targets, failed_volumes], - cache_fname=oci_utils.iscsiadm.ISCSIADM_CACHE) - did_something = True - except Exception as e: - _logger.error("Failed to configure device [%s]: %s", this_volume_data['iqn'], str(e)) - retval = 1 - else: - _logger.error('Volume [%s] not found.', iqn) - return did_something, retval + _logger.debug("Destroying volume [%s]", ocid) + try: + vol = sess.get_volume(ocid) + except Exception as e: + _logger.debug("Failed to retrieve Volume details", exc_info=True) + raise Exception("Failed to retrieve Volume details: %s" % ocid) from e + if vol is None: + raise Exception("Volume not found: %s" % ocid) -def ocid_refresh(wait=False): + if vol.is_attached(): + raise Exception("Cannot destroy an attached volume") + + try: + _logger.debug('destroying volume %s:%s', vol.get_display_name(), vol.get_ocid()) + vol.destroy() + except Exception as e: + _logger.debug("Failed to destroy volume %s", ocid, exc_info=True) + raise Exception("Failed to destroy volume") from e + + +def api_display_available_block_volumes(sess, compartments, show_all, output_mode, details, truncate): """ - Refresh OCID cached information; it runs - /usr/libexec/ocid command line with --refresh option + Display the available devices for the compartments specified. Parameters ---------- - wait: bool - Flag, wait until completion if set. + sess: OCISession + The OCISession instance. + compartments: list of str + compartement ocid(s) + show_all: bool + display all volumes. By default, display only not-attached ones + output_mode : information display mode + details : display detailed information ? + truncate: truncate text? Returns ------- - bool - True on success, False otherwise. + No return value. """ - _logger.debug('%s', where_am_i()) - _cmd = ['/usr/libexec/ocid', '--refresh', 'iscsi'] - if wait: - _cmd.append('--no-daemon') - try: - _logger.debug('Executing %s', _cmd) - output = subprocess.check_output(_cmd, stderr=subprocess.STDOUT).decode('utf-8').splitlines() - if _logger.isEnabledFor(logging.DEBUG): - _logger.debug('Ocid run output: %s', str(output)) - return True - except subprocess.CalledProcessError as e: - _logger.debug('Launch of ocid failed : %s', str(e)) - return False + _title = "Other available storage volumes:" + if sess is None: + _logger.info("Failed to create session, unable to show available volumes.") + return -def load_iscsi_admin_cache(): + vols = [] + if len(compartments) > 0: + # + # -C/--compartment option used + for cspec in compartments: + try: + if cspec == 'all': + vols = sess.all_volumes() + break + if cspec.startswith('ocid1.compartment.oc1..'): + # compartment specified with its ocid + comp = sess.get_compartment(ocid=cspec) + if comp is None: + _logger.error("Compartment not found: %s", cspec) + else: + cvols = comp.all_volumes() + vols += cvols + else: + # compartment specified with display name regexp + comps = sess.find_compartments(display_name=cspec) + if len(comps) == 0: + _logger.error("No compartments matching '%s' found", cspec) + else: + for comp in comps: + cvols = comp.all_volumes() + vols += cvols + except Exception as e: + _logger.error('Failed to get data for compartment %s: %s', cspec, str(e)) + else: + # + # -C/--compartment option wasn't used, default to the instance's own + # compartment + try: + comp = sess.this_compartment() + avail_domain = sess.this_availability_domain() + if comp is not None: + vols = comp.all_volumes(availability_domain=avail_domain) + _title = "Other available storage volumes %s/%s:" % (comp.get_display_name(), avail_domain) + else: + _logger.error("Compartment for this instance not found") + except Exception as e: + _logger.error('Failed to get data for this compartment: %s', str(e)) + + if len(vols) == 0: + _logger.info("No additional storage volumes found.") + return + + _vols_to_be_displayed = [] + for v in vols: + if v.is_attached() and not show_all: + continue + # display also the attached ones + _vols_to_be_displayed.append(v) + _vols_to_be_displayed.sort() + _display_oci_volume_list(_vols_to_be_displayed, output_mode, details, truncate) + + +def _do_attach_oci_block_volume(sess, ocid, chap=False): """ - Load the iscsiadm cache. + Make API calls to attach a volume with the given OCID to this instance. + Parameters + ---------- + sess : OCISession + An OCISession instance + ocid : str + The volume OCID + chap: bool + Set the Require Chap Credentials flag if True Returns ------- - tuple: targets, timestamp + OCIVolume + Raise: + Exception if attachment failed """ - _logger.debug('%s', where_am_i()) - ocid_cache = load_cache(global_file=iscsiadm.ISCSIADM_CACHE, max_age=timedelta(minutes=2))[1] - if ocid_cache is None: - _logger.debug('Updating the cache') - # run ocid once, to update the cache - ocid_refresh(wait=True) - # now try to load again - ocid_cache = load_cache(global_file=iscsiadm.ISCSIADM_CACHE, max_age=timedelta(minutes=2))[1] - if ocid_cache is None: - targets, attach_failed = None, None - else: - targets, attach_failed = ocid_cache - _logger.debug('iSCSI targets: %s', targets) - _logger.debug('Attach failed: %s', attach_failed) - return targets, attach_failed + _logger.debug('Attaching volume [%s]', ocid) + vol = sess.get_volume(ocid) + if vol is None: + raise Exception('Volume [%s] not found' % ocid) + if vol.is_attached(): + if vol.get_instance().get_ocid() == sess.this_instance().get_ocid(): + _msg = 'Volume [%s] already attached to this instance' % ocid + else: + _msg = 'Volume [%s] already attached to instance %s [%s]' % (ocid, + vol.get_instance().get_ocid(), + vol.get_instance().get_display_name()) + raise Exception(_msg) -def load_detached_volumes_cache(): + _logger.info('Attaching OCI Volume [%s] to this instance.', ocid) + # vol = vol.attach_to(instance_id=sess.this_instance().get_ocid(), wait=True) + vol = vol.attach_to(instance_id=sess.this_instance().get_ocid(), use_chap=chap, wait=True) + _logger.debug("Volume [%s] attached", ocid) + + return vol + + +def get_volume_by_iqn(sess, iqn): """ - Load the iqns of the detached volumes from the cache. + Gets a volume by given IQN + + Parameters + ---------- + sess: OCISession + The OCISEssion instance. + iqn: str + The iSCSI qualified name. Returns ------- - list: the iqns of the detached volumes. + OCIVolume : the found volume or None """ - # detached_vol_iqns = load_cache(__ignore_file)[1] - _logger.debug('%s', where_am_i()) - detached_vol_iqns = load_cache_11876(global_file=iscsiadm.IGNOREIQNS_CACHE, global_file_11876=__ignore_file)[1] - if detached_vol_iqns is None: - detached_vol_iqns = [] - _logger.debug('Detached volumes: %s', detached_vol_iqns) - return detached_vol_iqns + _logger.debug('Looking for volume with IQN == %s', iqn) + try: + if bool(sess): + get_volume_by_iqn.all_this_instance_volume = sess.this_instance().all_volumes() + for volume in get_volume_by_iqn.all_this_instance_volume: + if volume.get_iqn() == iqn: + _logger.debug('Found %s', str(volume)) + return volume + else: + _logger.info('Unable to get volume ocid and display name for iqn [%s], ', iqn) + except Exception as e: + _logger.debug('Failed to get volume data for iqn [%s]: %s', iqn, str(e), stack_info=True, exc_info=True) + _logger.error('Failed to get volume data for iqn [%s]', iqn) + return None -def do_sync(args): +def get_iqn_from_ocid(sess, ocid): """ - Syncronise iscsi block volumes. + Try to get the value for the iqn for a volume identified by an ocid, if any. Parameters ---------- - args: namespace - The commandline. + sess: OCISession + The OCISession instance. + ocid: str + The ocid. Returns ------- - bool: True on success, False otherwise. + str: the iqn. """ - _logger.debug('%s', where_am_i()) - # - # load iscsiadm-cache - targets, attach_failed = load_iscsi_admin_cache() - # - # load detached volumes cache - detached_volume_iqns = load_detached_volumes_cache() - # - if not detached_volume_iqns and not attach_failed: - # nothing to do, stop here - print("All known devices are attached.") - return True - # - # we still have volume not attached, process them. - # this one is as good as obsolete, ocid takes care of executing iscsiadm attach commands. - # and detached volume iqns contains volumes which are detached from oci instance - # - # create an oci_api session - oci_sess = get_oci_api_session() - # - return_value_d = 0 - synced_f = False - if detached_volume_iqns: - _logger.info("Detached devices:") - synced_d, return_value_d = sync_detached_devices(oci_sess, - detached_volume_iqns, - targets, - apply=args.apply, - interactive=args.interactive, - apply_yes=args.yes) - return_value_f = 0 - synced_d = False - if attach_failed: - _logger.info("Devices that could not be attached automatically:") - synced_f, return_value_f = sync_failed_attached(oci_sess, - attach_failed, - targets, - apply=args.apply, - interactive=args.interactive, - apply_yes=args.yes) - - ocid_refresh(wait=True) - return True if return_value_d + return_value_f == 0 else False + _logger.debug('Trying to find the iqn for volume [%s]', ocid) + this_compartment = sess.this_compartment() + this_availability_domain = sess.this_availability_domain() + all_volumes = this_compartment.all_volumes(this_availability_domain) + for vol in all_volumes: + try: + if vol.get_ocid() == ocid: + return vol.get_iqn() + except Exception as e: + _logger.debug('Failed to find the iqn for[%s]: %s', ocid, str(e)) + continue + return None -def get_compatibility_mode(args): +def _is_iqn_attached(sess, iqn): """ - Get the compatibility mode, compat = 0.11. + Verify if oci volume with iqn is attached to this instance. Parameters ---------- - args: namespace - The command line + sess: OCISession + The OCISession instance. + iqn: str + The iSCSI qualified name. Returns ------- - tuple: compat mode, output mode, details flag + str: the ocid """ - _logger.debug('%s', where_am_i()) - if 'compat' in args and args.compat is True: - # Display information as version 0.11 for compatibility reasons for few settings. - output_mode = 'compat' - details = True - compat_mode = 'compat' - else: - compat_mode = 'gen' - output_mode = args.output_mode if 'output_mode' in args else None - details = args.details if 'details' in args else None - _logger.debug('Compatibility mode: %s', compat_mode) - return compat_mode, output_mode, details + _logger.debug('Verifying if [%s] is attached to this instance.', iqn) + volume_data = get_volume_by_iqn(sess, iqn) + if volume_data is None: + return None + if volume_data.is_attached(): + return volume_data.get_ocid() + return None -def get_max_volumes(): +def do_umount(mountpoint): """ - Evaluate the number of configured volumes. + Unmount the given mountpoint. + Parameters + ---------- + mountpoint: str + The mountpoint. Returns ------- - int: the max number of volumes. + bool + True on success, False otherwise. """ - _logger.debug('%s', where_am_i()) - max_vol = OCIUtilsConfiguration.getint('iscsi', 'max_volumes') - if max_vol > MAX_VOLUMES_LIMIT: - _logger.error("Your configured max_volumes(%s) is over the limit(%s)", max_vol, MAX_VOLUMES_LIMIT) - max_vol = MAX_VOLUMES_LIMIT - return max_vol + try: + _logger.info("Unmounting %s", mountpoint) + subprocess.check_output(['/usr/bin/umount', mountpoint], stderr=subprocess.STDOUT) + return True + except subprocess.CalledProcessError as e: + _logger.error("Failed to unmount [%s]: %s", mountpoint, e.output) + return False + + +def unmount_device(session, iqn, disks): + """ + Unmount the partitions of the device with the specified iqn, if they are mounted. + + Parameters + ---------- + session: iscsiadm session + iscsiadm.session() + iqn: str + The iSCSI qualified name. + disks: dict + List of block devices. + + Returns + ------- + bool + True for success or the device is not mounted. + False if the device is mount and unmounting failed. + """ + _logger.debug('_Unmount device %s', iqn) + retval = True + # + # find mountpoints + _logger.debug('') + device = session[iqn]['device'] + if device not in disks: + return True + if not bool(disks[device]['partitions']): + # + # no partitions, maybe device mounted. + if bool(disks[device]['mountpoint']): + # + # volume has no partitions and is currently mounted + if not do_umount(disks[device]['mountpoint']): + retval = False + else: + _logger.debug('Volume %s not mounted', iqn) + else: + # + # partitions + partitions = disks[device]['partitions'] + for part in list(partitions.keys()): + if bool(partitions[part]['mountpoint']): + # the partition is mounted + _logger.debug('Volume %s mounted', partitions[part]['mountpoint']) + if not do_umount(partitions[part]['mountpoint']): + retval = False + else: + _logger.debug('Volume %s not mounted', partitions[part]['mountpoint']) + return retval def do_create_volume(sess, size, display_name, attach_it, detached, chap_credentials, mode): @@ -1797,7 +1604,7 @@ def do_create_volume(sess, size, display_name, attach_it, detached, chap_credent ------ Exception if something went wrong """ - _logger.debug('%s', where_am_i()) + try: _logger.info("Creating a new %d GB volume %s", size, display_name) inst = sess.this_instance() @@ -1806,6 +1613,8 @@ def do_create_volume(sess, size, display_name, attach_it, detached, chap_credent _logger.debug('\n availability_domain %s\n compartment_id %s', inst.get_availability_domain_name(), inst.get_compartment_id()) # + # GT + # vol = sess.create_volume(inst.get_compartment_id(), vol = sess.create_volume(sess.this_compartment().get_ocid(), inst.get_availability_domain_name(), size=size, @@ -1859,9 +1668,16 @@ def do_create_volume(sess, size, display_name, attach_it, detached, chap_credent # is a new volume, should not be in detached list if vol_iqn in detached: _logger.debug('Volume %s should not be in detached volumes list.', vol_iqn) + # detached.remove(vol_iqn) + # write_cache_11876(cache_content=list(set(detached)), + # cache_fname=iscsiadm.IGNOREIQNS_CACHE, + # cache_fname_11876=__ignore_file) # ocid_refresh(wait=True) # + # __GT__ might be a good idea if ocid service is running + # if not _wait_for_attached_cache(vol_iqn): + # _logger.debug('%s did not show up.', vol_iqn) return # # Something wrong if passing here. @@ -1875,301 +1691,363 @@ def do_create_volume(sess, size, display_name, attach_it, detached, chap_credent raise Exception('Failed to attach created volume: %s' % iscsiadm.error_message_from_code(retval)) -def do_create(args): +def add_chap_secret(iqn, user, password): """ - Create an iscsi block volume. + Save the login information for the given iqn in the chap secrets file. Parameters ---------- - args: namespace - The commandline. + iqn: str + The iSCSI qualified name. + user: str + The iscsiadm username. + password: str + The iscsiadm password. Returns ------- - bool: True on success, False otherwise. + No return value. """ - _logger.debug('%s', where_am_i()) - # - # evaluate the number of volumes - max_volumes = get_max_volumes() - # - # collect iscsi volume information - system_disks = lsblk.list_blk_dev() - # - # try to create an oci api session - oci_sess = get_oci_api_session() - # - # load detached volumes cache - detached_volume_iqns = load_detached_volumes_cache() - # - # set the compatibility parameters, if necessary - compatibility_mode, args.output_mode, args.details = get_compatibility_mode(args) - # - if len(system_disks) > max_volumes: - _logger.error("This instance reached the max_volumes(%s)", max_volumes) - return 1 - try: - if bool(oci_sess): - do_create_volume(oci_sess, - size=args.size, - display_name=args.volume_name, - attach_it=args.attach_volume, - detached=detached_volume_iqns, - chap_credentials=args.chap, - mode=compatibility_mode) - else: - _logger.info('Unable to create volume, failed to create a session.') - return False - except Exception as e: - _logger.debug('Volume creation has failed: %s', str(e), stack_info=True, exc_info=True) - _logger.error('Volume creation has failed: %s', str(e)) - return False + # _, chap_passwords = load_cache(__chap_password_file) + _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, + global_file_11876=__chap_password_file) + if chap_passwords is None: + chap_passwords = {} + chap_passwords[iqn] = (user, password) + # write_cache(cache_content=chap_passwords, cache_fname=__chap_password_file, mode=0o600) + write_cache_11876(cache_content=chap_passwords, + cache_fname=iscsiadm.CHAPSECRETS_CACHE, + cache_fname_11876=__chap_password_file, + mode=0o600) - ocid_refresh(wait=True) - return True +def remove_chap_secret(iqn_ocid): + """ + Remove the login information for a given iqn from the chap secrets file. -def get_iqn_from_ocid(sess, ocid): + Parameters + ---------- + iqn_ocid: str + The iSCSI qualified name + + Returns + ------- + str: cache file timestamp on success, None otherwise """ - Try to get the value for the iqn for a volume identified by an ocid, if any. + _logger.debug('Remove %s from chap secret cache', iqn_ocid) + ret_value = None + # _, chap_passwords = load_cache(__chap_password_file) + _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, + global_file_11876=__chap_password_file) + if not bool(chap_passwords): + return ret_value + + iqn, _ = get_iqn_from_chap_secrets_cache(iqn_ocid)[0] if iqn_ocid.startswith(oci_volume_tag) else iqn_ocid, None + + if iqn in chap_passwords.keys(): + removed_values = chap_passwords.pop(iqn) + # ret_value = write_cache(cache_content=chap_passwords, cache_fname=__chap_password_file, mode=0o600) + ret_value = write_cache_11876(cache_content=chap_passwords, + cache_fname=iscsiadm.CHAPSECRETS_CACHE, + cache_fname_11876=__chap_password_file, + mode=0o600) + return ret_value + + +def get_chap_secret(iqn): + """ + Look for a saved (user,password) pair for iqn in the chap secrets file. Parameters ---------- - sess: OCISession - The OCISession instance. - ocid: str - The ocid. + iqn: str + The iSCSI qualified name. Returns ------- - str: the iqn. + tuple + The (timestamp, password) on success, (None,None) otherwise. + """ - _logger.debug('%s: %s', where_am_i(), ocid) - this_compartment = sess.this_compartment() - this_availability_domain = sess.this_availability_domain() - all_volumes = this_compartment.all_volumes(this_availability_domain) - for vol in all_volumes: - try: - if vol.get_ocid() == ocid: - return vol.get_iqn() - except Exception as e: - _logger.debug('Failed to find the iqn for[%s]: %s', ocid, str(e)) - continue + # _, chap_passwords = load_cache(__chap_password_file) + _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, + global_file_11876=__chap_password_file) + if chap_passwords is None: + return None, None + if iqn in chap_passwords: + return chap_passwords[iqn] + return None, None + + +def get_portal_ip_from_iscsiadm_cache(iqn_x): + """ + Try to retrieve the portal ip from the iscsiadm cache. + + Parameters + ---------- + iqn_x: str + The iqn + + Returns + ------- + str: the portal ip if found, None otherwise + """ + _, iscsi_cache = load_cache(global_file=iscsiadm.ISCSIADM_CACHE) + for portal in iscsi_cache: + for p_ip, iqn_list in portal.items(): + if iqn_x in iqn_list: + return p_ip return None -def do_destroy_volume(sess, ocid): +def get_iqn_from_chap_secrets_cache(ocid): + """ + Try to retrieve iqn and pw for volume ocid from chap secrets cache. + + Parameters + ---------- + ocid: str + The ocid/username of the volume. + + Returns + ------- + tuple: (iqn, password) if found, (None, None) otherwise + """ + # _, chap_passwords = load_cache(__chap_password_file) + _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, + global_file_11876=__chap_password_file) + if chap_passwords is None: + return None, None + for iqn, unpw in chap_passwords.items(): + if ocid == unpw[0]: + return iqn, unpw[1] + return None, None + + +def show_volumes(oci_session, iscsiadm_session, system_disks, args): + """ + Show iscsi volumes. + + Parameters + ---------- + oci_session: OCISession + The oci session. + iscsiadm_session: dict + The iscsiadm session. + system_disks: dict + The attached volumes. + args: namespace + The command line arguments. + + Returns + ------- + bool: True + """ + _logger.debug('Showing volumes.') + display_attached_volumes(oci_session, + iscsiadm_session, + system_disks, + args.output_mode, + args.details, + not args.no_truncate) + if len(args.compartments) > 0 or args.all: + api_display_available_block_volumes(oci_session, + args.compartments, + args.all, + args.output_mode, + args.details, + not args.no_truncate) + return True + + +def get_this_instance_ocid(session): + """ + Get the ocid of the current instance, via the api or via the metadata. + + Parameters + ---------- + session: OCISession + The oci session. + + Returns + ------- + str: the ocid + """ + if bool(session): + if bool(session.this_instance()): + return session.this_instance().get_ocid() + _logger.error('Failed to retrieve instance information.') + sys.exit(1) + else: + return get_instance_ocid() + + +def get_compatibility_mode(args): + """ + Get the compatibility mode, compat = 0.11. + + Parameters + ---------- + args: namespace + The command line + + Returns + ------- + tuple: compat mode, output mode, details flag + """ + if 'compat' in args and args.compat is True: + # Display information as version 0.11 for compatibility reasons for few settings. + output_mode = 'compat' + details = True + compat_mode = 'compat' + else: + compat_mode = 'gen' + output_mode = args.output_mode if 'output_mode' in args else None + details = args.details if 'details' in args else None + _logger.debug('Compatibility mode: %s', compat_mode) + return compat_mode, output_mode, details + + +def load_iscsi_admin_cache(): + """ + Load the iscsiadm cache. + + Returns + ------- + tuple: targets, timestamp + """ + ocid_cache = load_cache(global_file=iscsiadm.ISCSIADM_CACHE, + max_age=timedelta(minutes=2))[1] + if ocid_cache is None: + _logger.debug('Updating the cache') + # run ocid once, to update the cache + ocid_refresh(wait=True) + # now try to load again + ocid_cache = load_cache(global_file=iscsiadm.ISCSIADM_CACHE, + max_age=timedelta(minutes=2))[1] + if ocid_cache is None: + targets, attach_failed = None, None + else: + targets, attach_failed = ocid_cache + _logger.debug('iSCSI targets: %s', targets) + _logger.debug('Attach failed: %s', attach_failed) + return targets, attach_failed + + +def _is_iqn_in_iscsiadm_cache(iqn): """ - Destroy the volume with the given ocid. - The volume must be detached. This is just an added measure to - prevent accidentally destroying the wrong volume. - - Add root privilege requirement to be the same as create_volumerequirement. + Verify if iqn is in attached volumes cache. Parameters ---------- - sess: OCISession - The OCI service session. - ocid: str - The OCID. + iqn: str + The iqn. Returns ------- - None - Raise - ----- - Exception : when destroy has failed + bool: True on success, False otherwise. """ - _logger.debug('%s: %s', where_am_i(), ocid) - try: - vol = sess.get_volume(ocid) - except Exception as e: - _logger.debug("Failed to retrieve Volume details", exc_info=True) - raise Exception("Failed to retrieve Volume details: %s" % ocid) from e - - if vol is None: - raise Exception("Volume not found: %s" % ocid) - - if vol.is_attached(): - raise Exception("Cannot destroy an attached volume") - - try: - _logger.debug('destroying volume %s:%s', vol.get_display_name(), vol.get_ocid()) - vol.destroy() - except Exception as e: - _logger.debug("Failed to destroy volume %s", ocid, exc_info=True) - raise Exception("Failed to destroy volume") from e + _logger.debug('__Verifying if [%s] is in attched cache.', iqn) + iscsisadmcache, failedattached = load_iscsi_admin_cache() + if iscsisadmcache is None: + return False + for _, iqns in iscsisadmcache.items(): + if iqn in iqns: + _logger.debug('Found %s in attached volume cache.', iqn) + return True + return False -def do_destroy(args): +def _wait_for_attached_cache(iqn): """ - Destroy an iscsi block volume. + Waiting loop for iqn of a volume is going to show up in the attached volume cache. Parameters ---------- - args: namespace - The commandline. + iqn: str + The iqn Returns ------- bool: True on success, False otherwise. """ - _logger.debug('%s', where_am_i()) - # - # try to create an oci api session - oci_sess = get_oci_api_session() - # - # load detached volumes cache - detached_volume_iqns = load_detached_volumes_cache() - retval = True - if not args.yes: - for ocid in args.ocids: - _logger.info("Volume : [%s]", ocid) - if not _read_yn('WARNING: the volume(s) will be destroyed. This is irreversible. Continue?', - yn=True, - waitenter=True, - suppose_yes=False, - default_yn=False): + for _ in range(cache_loop): + if _is_iqn_in_iscsiadm_cache(iqn): return True - for ocid in args.ocids: - try: - if bool(oci_sess): - _logger.debug('Destroying [%s]', ocid) - # - # try to get the iqn from a detached volume - _iqn = get_iqn_from_ocid(oci_sess, ocid) - do_destroy_volume(oci_sess, ocid) - _ = remove_chap_secret(ocid) - _logger.info("Volume [%s] is destroyed", ocid) - # - # remove iqn from ignore list. - if bool(_iqn): - if _iqn in detached_volume_iqns: - detached_volume_iqns.remove(_iqn) - write_cache_11876(cache_content=list(set(detached_volume_iqns)), - cache_fname=iscsiadm.IGNOREIQNS_CACHE, - cache_fname_11876=__ignore_file) - _logger.debug('%s removed from cache.', _iqn) - else: - _logger.info('Unable to destroy volume, failed to create a session.') - retval = False - except Exception as e: - _logger.debug('Volume [%s] deletion has failed: %s', ocid, str(e), stack_info=True, exc_info=True) - _logger.error('Volume [%s] deletion has failed: %s', ocid, str(e)) - retval = False - - return retval + _logger.debug('%s in not in attached volumes list, ' + 'wait for ocid refresh to complete and give it another try.', iqn) + time.sleep(cache_delay) + return False -def add_chap_secret(iqn, user, password): +def _wait_for_detached_cache(iqn): """ - Save the login information for the given iqn in the chap secrets file. + Waiting loop for iqn disappearing from detached volumes cache. Parameters ---------- iqn: str - The iSCSI qualified name. - user: str - The iscsiadm username. - password: str - The iscsiadm password. + The iqn. Returns ------- - No return value. + bool: True on success, False otherwise """ - # _, chap_passwords = load_cache(__chap_password_file) - _logger.debug('%s', where_am_i()) - _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, - global_file_11876=__chap_password_file) - if chap_passwords is None: - chap_passwords = {} - chap_passwords[iqn] = (user, password) - # write_cache(cache_content=chap_passwords, cache_fname=__chap_password_file, mode=0o600) - write_cache_11876(cache_content=chap_passwords, - cache_fname=iscsiadm.CHAPSECRETS_CACHE, - cache_fname_11876=__chap_password_file, - mode=0o600) + for _ in range(cache_loop): + detachedvolumecache = load_detached_volumes_cache() + if iqn in detachedvolumecache: + _logger.debug('%s is still in detached volumes list, ' + 'wait for ocid refresh to complete and give it another try.', iqn) + time.sleep(cache_delay) + else: + return True + return False -def get_iqn_from_chap_secrets_cache(ocid): +def load_detached_volumes_cache(): """ - Try to retrieve iqn and pw for volume ocid from chap secrets cache. - - Parameters - ---------- - ocid: str - The ocid/username of the volume. + Load the iqns of the detached volumes from the cache. Returns ------- - tuple: (iqn, password) if found, (None, None) otherwise + list: the iqns of the detached volumes. """ - # _, chap_passwords = load_cache(__chap_password_file) - _logger.debug('%s', where_am_i()) - _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, - global_file_11876=__chap_password_file) - if chap_passwords is None: - return None, None - for iqn, unpw in chap_passwords.items(): - if ocid == unpw[0]: - return iqn, unpw[1] - return None, None + # detached_vol_iqns = load_cache(__ignore_file)[1] + detached_vol_iqns = load_cache_11876(global_file=iscsiadm.IGNOREIQNS_CACHE, + global_file_11876=__ignore_file)[1] + if detached_vol_iqns is None: + detached_vol_iqns = [] + _logger.debug('Detached volumes: %s', detached_vol_iqns) + return detached_vol_iqns -def remove_chap_secret(iqn_ocid): +def get_max_volumes(): """ - Remove the login information for a given iqn from the chap secrets file. - - Parameters - ---------- - iqn_ocid: str - The iSCSI qualified name + Evaluate the number of configured volumes. Returns ------- - str: cache file timestamp on success, None otherwise + int: the max number of volumes. """ - _logger.debug('%s: %s', where_am_i(), iqn_ocid) - ret_value = None - # _, chap_passwords = load_cache(__chap_password_file) - _, chap_passwords = load_cache_11876(global_file=iscsiadm.CHAPSECRETS_CACHE, - global_file_11876=__chap_password_file) - if not bool(chap_passwords): - return ret_value - - iqn, _ = get_iqn_from_chap_secrets_cache(iqn_ocid)[0] if iqn_ocid.startswith(oci_volume_tag) else iqn_ocid, None - - if iqn in chap_passwords.keys(): - removed_values = chap_passwords.pop(iqn) - # ret_value = write_cache(cache_content=chap_passwords, cache_fname=__chap_password_file, mode=0o600) - ret_value = write_cache_11876(cache_content=chap_passwords, - cache_fname=iscsiadm.CHAPSECRETS_CACHE, - cache_fname_11876=__chap_password_file, - mode=0o600) - return ret_value + max_vol = OCIUtilsConfiguration.getint('iscsi', 'max_volumes') + if max_vol > MAX_VOLUMES_LIMIT: + _logger.error("Your configured max_volumes(%s) is over the limit(%s)", max_vol, MAX_VOLUMES_LIMIT) + max_vol = MAX_VOLUMES_LIMIT + return max_vol -def get_portal_ip_from_iscsiadm_cache(iqn_x): +def get_iscsiadm_session(): """ - Try to retrieve the portal ip from the iscsiadm cache. - - Parameters - ---------- - iqn_x: str - The iqn + Find the attached block volumes, except the boot volume. Returns ------- - str: the portal ip if found, None otherwise + dict: the attached block volumes and their data. """ - _logger.debug('%s', where_am_i()) - _, iscsi_cache = load_cache(global_file=iscsiadm.ISCSIADM_CACHE) - for portal in iscsi_cache: - for p_ip, iqn_list in portal.items(): - if iqn_x in iqn_list: - return p_ip - return None + + all_volumes = iscsiadm.session() + iscsiadmsession = dict((iqn, all_volumes[iqn]) for iqn in all_volumes if 'boot:uefi' not in iqn) + return iscsiadmsession def do_oci_vol_attach_ocid(oci_session, compatibility_mode, volume_iqn, use_chap_secrets): @@ -2191,7 +2069,6 @@ def do_oci_vol_attach_ocid(oci_session, compatibility_mode, volume_iqn, use_chap ------- dict: the attachment data. """ - _logger.debug('%s', where_am_i()) bs_volume = None try: if bool(oci_session): @@ -2211,86 +2088,22 @@ def do_oci_vol_attach_ocid(oci_session, compatibility_mode, volume_iqn, use_chap mode=compatibility_mode) # user/pass coming from volume itself attach_data = dict() - attach_data['attachment_username'] = bs_volume.get_user() - attach_data['attachment_password'] = bs_volume.get_password() - attach_data['iscsi_portal_ip'] = bs_volume.get_portal_ip() - attach_data['iqn_to_use'] = bs_volume.get_iqn() - attach_data['save_chap_cred'] = bool(use_chap_secrets) - _logger.debug('Attach data: %s', attach_data) - return attach_data - - _logger.info('Unable to attach volume, failed to create a session.') - return False - except Exception as e: - _logger.debug('Failed to attach volume [%s]: %s', volume_iqn, str(e), - stack_info=True, - exc_info=True) - _logger.error('Failed to attach volume [%s]: %s', volume_iqn, str(e)) - return False - - -def _is_iqn_attached(sess, iqn): - """ - Verify if oci volume with iqn is attached to this instance. - - Parameters - ---------- - sess: OCISession - The OCISession instance. - iqn: str - The iSCSI qualified name. - - Returns - ------- - str: the ocid - """ - _logger.debug('%s: %s', where_am_i(), iqn) - volume_data = get_volume_by_iqn(sess, iqn) - if volume_data is None: - return None - if volume_data.is_attached(): - return volume_data.get_ocid() - return None - - -def _do_attach_oci_block_volume(sess, ocid, chap=False): - """ - Make API calls to attach a volume with the given OCID to this instance. - - Parameters - ---------- - sess : OCISession - An OCISession instance - ocid : str - The volume OCID - chap: bool - Set the Require Chap Credentials flag if True - Returns - ------- - OCIVolume - Raise: - Exception if attachment failed - """ - _logger.debug('%s: %s', where_am_i(), ocid) - vol = sess.get_volume(ocid) - if vol is None: - raise Exception('Volume [%s] not found' % ocid) - - if vol.is_attached(): - if vol.get_instance().get_ocid() == sess.this_instance().get_ocid(): - _msg = 'Volume [%s] already attached to this instance' % ocid - else: - _msg = 'Volume [%s] already attached to instance %s [%s]' % (ocid, - vol.get_instance().get_ocid(), - vol.get_instance().get_display_name()) - raise Exception(_msg) - - _logger.info('Attaching OCI Volume [%s] to this instance.', ocid) - # vol = vol.attach_to(instance_id=sess.this_instance().get_ocid(), wait=True) - vol = vol.attach_to(instance_id=sess.this_instance().get_ocid(), use_chap=chap, wait=True) - _logger.debug("Volume [%s] attached", ocid) + attach_data['attachment_username'] = bs_volume.get_user() + attach_data['attachment_password'] = bs_volume.get_password() + attach_data['iscsi_portal_ip'] = bs_volume.get_portal_ip() + attach_data['iqn_to_use'] = bs_volume.get_iqn() + attach_data['save_chap_cred'] = bool(use_chap_secrets) + _logger.debug('Attach data: %s', attach_data) + return attach_data - return vol + _logger.info('Unable to attach volume, failed to create a session.') + return False + except Exception as e: + _logger.debug('Failed to attach volume [%s]: %s', volume_iqn, str(e), + stack_info=True, + exc_info=True) + _logger.error('Failed to attach volume [%s]: %s', volume_iqn, str(e)) + return False def do_oci_vol_attach_iqn(oci_session, iscsiadm_session, volume_iqn, chap_username, chap_password): @@ -2316,7 +2129,6 @@ def do_oci_vol_attach_iqn(oci_session, iscsiadm_session, volume_iqn, chap_userna """ # # iqn is not in iscsiadm session ... might also not be in this_instance volume list.. - _logger.debug('%s', where_am_i()) this_ocid = _is_iqn_attached(oci_session, volume_iqn) if not this_ocid: # @@ -2351,389 +2163,172 @@ def do_oci_vol_attach_iqn(oci_session, iscsiadm_session, volume_iqn, chap_userna return attach_data -def _do_iscsiadm_attach(iqn, targets, user=None, passwd=None, iscsi_portal_ip=None): - """ - Attach an iSCSI device. - - Parameters - ---------- - iqn: str - The iSCSI qualified name. - targets: dict - The targets, - user: str - The iscsiadm username. - passwd: str - The iscsiadm user password. - iscsi_portal_ip: str - portal IP - Returns - ------- - None - Raise - ----- - Exception in case of error - """ - _logger.debug('%s', where_am_i()) - if not iscsi_portal_ip: - portal_ip = None - if targets is None: - raise Exception("Ocid service must be running to determine the portal IP address for this device.") - - for ipaddr in list(targets.keys()): - if iqn in targets[ipaddr]: - portal_ip = ipaddr - if portal_ip is None: - # - # this shouldn't really happen, but just in case - raise Exception("Can't find portal IP address") - else: - portal_ip = iscsi_portal_ip - - _logger.debug('Portal: ip %s; iqn: %s; user %s; passwd: %s', portal_ip, iqn, user, passwd) - retval = iscsiadm.attach(portal_ip, 3260, iqn, user, passwd, auto_startup=True) - - if retval != 0: - _logger.info("Result: %s", iscsiadm.error_message_from_code(retval)) - raise Exception('iSCSI attachment failed: %s' % iscsiadm.error_message_from_code(retval)) - - -def do_attach(args): - """ - Attach an iscsi block volume. - - Parameters - ---------- - args: namespace - The commandline. - - Returns - ------- - bool: True on success, False otherwise. - """ - _logger.debug('%s', where_am_i()) - # - # collect iscsi volume information - system_disks = lsblk.list_blk_dev() - # - # evaluate the number of volumes - max_volumes = get_max_volumes() - # - # we are not touching boot volume in iscsi config - iscsiadm_session = iscsiadm.session() - # - # try to create an oci api session - oci_sess = get_oci_api_session() - # - # set the compatibility parameters, if necessary - compatibility_mode, args.output_mode, args.details = get_compatibility_mode(args) - # - # load iscsiadm-cache - targets, attach_failed = load_iscsi_admin_cache() - # - # load detached volumes cache - detached_volume_iqns = load_detached_volumes_cache() - # - # maximum number of volumes reached - if len(system_disks) > max_volumes: - _logger.error("This instance reached the maximum number of volumes attached (%s)", max_volumes) - return False - - if bool(args.ocids): - iqnocid = args.ocids - elif bool(args.iqns): - iqnocid = args.iqns - else: - # should be trapped by argparse, one of those is required. - _logger.error('Missing iqns or ocids') - return False - - retval = True - for iqnorocid in iqnocid: - _save_chap_cred = False - if iqnorocid in iscsiadm_session: - _logger.info("Target [%s] is already attached.", iqnorocid) - continue - - if iqnorocid.startswith(oci_volume_tag): - # - # ocid - _logger.debug('Given IQN [%s] is probably an ocid, attaching it', iqnorocid) - - attach_data = do_oci_vol_attach_ocid(oci_sess, compatibility_mode, iqnorocid, args.chap) - if not bool(attach_data): - retval = False - continue - elif iqnorocid.startswith(iqn_tag): - # - # iqn - _logger.debug('Given IQN [%s] is probably an iqn, attaching it', iqnorocid) - - attach_data = do_oci_vol_attach_iqn(oci_sess, iscsiadm_session, iqnorocid, args.username, args.password) - if not bool(attach_data): - retval = False - continue - else: - # - # invalid parameter - _logger.info('Invalid argument, given IQN [%s] is not an iqn nor an ocid.', iqnorocid) - retval = False - continue - # - _logger.debug('Attaching [%s] to iSCSI session', iqnorocid) - try: - _do_iscsiadm_attach(attach_data['iqn_to_use'], - targets, - user=attach_data['attachment_username'], - passwd=attach_data['attachment_password'], - iscsi_portal_ip=attach_data['iscsi_portal_ip']) - _logger.debug('Attachment of %s succeeded.', iqnorocid) - if attach_data['iqn_to_use'] in detached_volume_iqns: - _logger.debug('Volume %s was detached, remove from detached list.', iqnorocid) - detached_volume_iqns.remove(attach_data['iqn_to_use']) - write_cache_11876(cache_content=list(set(detached_volume_iqns)), - cache_fname=iscsiadm.IGNOREIQNS_CACHE, - cache_fname_11876=__ignore_file) - if args.chap: - _logger.debug('Attachment OK: saving chap credentials.') - add_chap_secret(iqnorocid, attach_data['attachment_username'], attach_data['attachment_password']) - except Exception as e: - _logger.debug("Failed to attach target [%s]: %s", iqnorocid, str(e), exc_info=True, stack_info=True) - _logger.error("Failed to attach target [%s]: %s", iqnorocid, str(e)) - _save_chap_cred = False - retval = False - continue - - if retval: - _logger.debug('Trigger ocid refresh.') - ocid_refresh(wait=True) - - return retval - - -def _wait_for_detached_cache(iqn): - """ - Waiting loop for iqn disappearing from detached volumes cache. - - Parameters - ---------- - iqn: str - The iqn. - - Returns - ------- - bool: True on success, False otherwise - """ - _logger.debug('%s', where_am_i()) - for _ in range(cache_loop): - detachedvolumecache = load_detached_volumes_cache() - if iqn in detachedvolumecache: - _logger.debug('%s is still in detached volumes list, ' - 'wait for ocid refresh to complete and give it another try.', iqn) - time.sleep(cache_delay) - else: - return True - return False - - -def do_detach_volume(oci_session, iscsiadm_session, iqn, mode): +def sync_detached_devices(oci_session, detached_volumes, targets, apply=False, interactive=False, apply_yes=False): """ - Detach the volume with given IQN + Try to attach volumes in the detached volumes list. Parameters ---------- oci_session: OCISession - The oci session. - iscsiadm_session: - iscsiadm session - iqn: str - The IQN. - mode: str - Show output in 0.11 compatibility mode is set to 'compat' - - Returns - ------- - None - Raise - ----- - Exception : when destroy has failed - """ - _logger.debug('%s', where_am_i()) - _volume = get_volume_by_iqn(oci_session, iqn) - if _volume is None: - raise Exception("Volume with IQN [%s] not found" % iqn) - try: - compat_info_message(compat_msg="Detaching volume", - gen_msg="Detaching volume %s [%s]" % (_volume.get_display_name(), - _volume.get_iqn()), mode=mode) - _volume.detach() - except Exception as e: - _logger.debug("Failed to disconnect volume", exc_info=True) - _logger.error('%s', str(e)) - raise Exception("Failed to disconnect volume %s" % iqn) from e - - _logger.debug('Volume detached, detaching it from iSCSI session') - if not iscsiadm.detach(iscsiadm_session[iqn]['persistent_portal_ip'], - iscsiadm_session[iqn]['persistent_portal_port'], - iqn): - raise Exception("Failed to detach target %s" % iqn) - - -def do_umount(mountpoint): - """ - Unmount the given mountpoint. - - Parameters - ---------- - mountpoint: str - The mountpoint. - Returns - ------- - bool - True on success, False otherwise. - """ - _logger.debug('%s', where_am_i()) - try: - _logger.info("Unmounting %s", mountpoint) - subprocess.check_output(['/usr/bin/umount', mountpoint], stderr=subprocess.STDOUT) - return True - except subprocess.CalledProcessError as e: - _logger.error("Failed to unmount [%s]: %s", mountpoint, e.output) - return False - - -def unmount_device(session, iqn, disks): - """ - Unmount the partitions of the device with the specified iqn, if they are mounted. - - Parameters - ---------- - session: iscsiadm session - iscsiadm.session() - iqn: str - The iSCSI qualified name. - disks: dict - List of block devices. + The oci api session. + detached_volumes: list + The iqn's of the detached volumes. + targets: dict + The targets. + apply: bool + Try to attach if True. + interactive: bool + Compatiblity flag, Try to attach if True. + apply_yes: bool + Assume yes if True. Returns ------- - bool - True for success or the device is not mounted. - False if the device is mount and unmounting failed. + tuple: (bool, int) + Something changed/[0,1] """ - _logger.debug('%s: %s', where_am_i(), iqn) - retval = True - # - # find mountpoints - _logger.debug('') - device = session[iqn]['device'] - if device not in disks: - return True - if not bool(disks[device]['partitions']): - # - # no partitions, maybe device mounted. - if bool(disks[device]['mountpoint']): - # - # volume has no partitions and is currently mounted - if not do_umount(disks[device]['mountpoint']): - retval = False + did_something = False + retval = 0 + for iqn in detached_volumes: + # display_detached_iscsi_device(iqn, targets) + this_volume_data = get_volume_data_from_(iqn, oci_session) + if not this_volume_data: + _logger.error('Volume with iqn %s does not exist.', iqn) + # if invalid iqn in detached volume list, clean up + if apply or interactive: + if apply_yes: + ans = True + else: + ans = _read_yn('Would you like to remove %s from detached volume list?' % iqn, + yn=True, + waitenter=True, + suppose_yes=False, + default_yn=False) + if ans: + detached_volumes.remove(iqn) + write_cache_11876(cache_content=list(set(detached_volumes)), + cache_fname=iscsiadm.IGNOREIQNS_CACHE, + cache_fname_11876=__ignore_file) else: - _logger.debug('Volume %s not mounted', iqn) - else: - # - # partitions - partitions = disks[device]['partitions'] - for part in list(partitions.keys()): - if bool(partitions[part]['mountpoint']): - # the partition is mounted - _logger.debug('Volume %s mounted', partitions[part]['mountpoint']) - if not do_umount(partitions[part]['mountpoint']): - retval = False - else: - _logger.debug('Volume %s not mounted', partitions[part]['mountpoint']) - return retval + _ = display_iscsi_device(this_volume_data) + if apply or interactive: + if apply_yes: + ans = True + else: + ans = _read_yn('Would you like to attach this device?', + yn=True, + waitenter=True, + suppose_yes=False, + default_yn=False) + if ans: + try: + chap = True if this_volume_data['chap_user'] is not None else False + attach_data = do_oci_vol_attach_ocid(oci_session, 'gen', this_volume_data['ocid'], chap) + # _do_iscsiadm_attach(this_volume_data['iqn'], + # targets, + # user=this_volume_data['chap_user'], + # passwd=this_volume_data['chap_pw'], + # iscsi_portal_ip=this_volume_data['portal_ip']) + detached_volumes.remove(this_volume_data['iqn']) + write_cache_11876(cache_content=list(set(detached_volumes)), + cache_fname=iscsiadm.IGNOREIQNS_CACHE, + cache_fname_11876=__ignore_file) + did_something = True + except Exception as e: + _logger.error('[%s] attachment failed: %s', iqn, str(e)) + retval = 1 + return did_something, retval -def do_detach(args): +def sync_failed_attached(oci_session, failed_volumes, targets, apply=False, interactive=False, apply_yes=False): """ - Detach an iscsi block volume. - + Try to attach volumes in the failed attached volumes list. Parameters ---------- - args: namespace - The commandline. + oci_session: OCISession + The oci api session. + failed_volumes: list + The iqn's of volumes failed attachment. + targets: list + The targets. + apply: bool + Try to attach if True. + interactive: bool + Compatiblity flag, Try to attach if True. + apply_yes: bool + Assume yes if True. Returns ------- - bool: True on success, False otherwise. + tuple: (bool, int) + Something changed/[0,1] """ - _logger.debug('%s', where_am_i()) - # - # we are not touching boot volume in iscsi config - iscsiadm_session = iscsiadm.session() - # - # collect iscsi volume information - system_disks = lsblk.list_blk_dev() - # - # try to create an oci api session - oci_sess = get_oci_api_session() - # - # set the compatibility parameters, if necessary - compatibility_mode, args.output_mode, args.details = get_compatibility_mode(args) - # - # load detached volumes cache - detached_volume_iqns = load_detached_volumes_cache() - # - return_value = True - for iqn in args.iqns: - retval = True - if not _wait_for_detached_cache(iqn): - _logger.error("Target [%s] is already detached", iqn) - retval = False - # continue - if iqn not in iscsiadm_session or 'device' not in iscsiadm_session[iqn]: - _logger.error("Target [%s] not found", iqn) - retval = False - # continue - if retval: - _logger.debug('Unmounting the block volume') - if not unmount_device(iscsiadm_session, iqn, system_disks): - _logger.debug('Unmounting has failed') - if not args.force: - # if not ask_yes_no("Failed to unmount volume, Continue detaching anyway?"): - if not _read_yn('Failed to unmount volume, Continue detaching anyway?', - yn=True, - waitenter=True, - suppose_yes=False, - default_yn=False): - continue - else: - _logger.info('Unmount failed, force option selected,continue anyway.') - try: - if bool(oci_sess): - _logger.debug('Detaching [%s]', iqn) - do_detach_volume(oci_sess, iscsiadm_session, iqn, mode=compatibility_mode) - compat_info_message(gen_msg="Volume [%s] is detached." % iqn, mode=compatibility_mode) - detached_volume_iqns.append(iqn) - write_cache_11876(cache_content=list(set(detached_volume_iqns)), - cache_fname=iscsiadm.IGNOREIQNS_CACHE, - cache_fname_11876=__ignore_file) + did_something = False + retval = 0 + for iqn in list(failed_volumes.keys()): + # display_detached_iscsi_device(iqn, targets, attach_failed) + this_volume_data = get_volume_data_from_(iqn, oci_session) + if this_volume_data: + _ = display_iscsi_device(this_volume_data) + _attach_user_name = None + _attach_user_passwd = None + _give_it_a_try = False + if apply or interactive: + if failed_volumes[iqn] != 24: + # not authentication error + # if args.yes or ask_yes_no("Would you like to retry attaching this device?"): + if _read_yn('Would you like to retry attaching this device?', + yn=True, + waitenter=True, + suppose_yes=False, + default_yn=False): + _give_it_a_try = True else: - _logger.info('Unable to detach volume, failed to create a session.') - retval = False - except Exception as e: - _logger.debug('Volume [%s] detach has failed: %s', iqn, str(e), stack_info=True, exc_info=True) - _logger.error('Volume [%s] detach has failed: %s', iqn, str(e)) - retval = 1 - - if retval: - pass + _logger.debug('%s in failed list because of authorisation failure.', iqn) + # authentication error + # if args.yes or ask_yes_no("Would you like to configure this device?"): + if apply_yes or _read_yn('Would you like to configure this device?', + yn=True, + waitenter=True, + suppose_yes=False, + default_yn=False): + _give_it_a_try = True + if oci_session is not None: + # oci_vols = oci_session.find_volumes(iqn=iqn) + # if len(oci_vols) != 1: + # _logger.error('volume [%s] not found', iqn) + # _give_it_a_try = False + this_volume_data = get_volume_data_from_(iqn, oci_session) + # _attach_user_name = oci_vols[0].get_user() + # _attach_user_passwd = oci_vols[0].get_password() + _attach_user_name = this_volume_data['chap_user'] + _attach_user_passwd = this_volume_data['chap_pw'] + else: + (_attach_user_name, _attach_user_passwd) = get_chap_secret(iqn) + if _attach_user_name is None: + _logger.error('Cannot retreive chap credentials') + _give_it_a_try = False + if _give_it_a_try: + try: + chap = True if this_volume_data['chap_user'] is not None else False + attach_data = do_oci_vol_attach_ocid(oci_session, 'gen', this_volume_data['ocid'], chap) + failed_volumes = {key:failed_volumes[key] + for key in failed_volumes if key != this_volume_data['iqn']} + # failed_volumes.remove(this_volume_data['iqn']) + write_cache(cache_content=[targets, failed_volumes], + cache_fname=oci_utils.iscsiadm.ISCSIADM_CACHE) + # try: + # _do_iscsiadm_attach(iqn, + # targets, + # user=_attach_user_name, + # passwd=_attach_user_passwd) + did_something = True + except Exception as e: + _logger.error("Failed to configure device [%s]: %s", this_volume_data['iqn'], str(e)) + retval = 1 else: - return_value = retval - - _logger.debug('Trigger ocid refresh') - ocid_refresh(wait=True) - return return_value + _logger.error('Volume [%s] not found.', iqn) + return did_something, retval _this_instance_ocid = None @@ -2746,20 +2341,10 @@ def main(): Returns ------- int - 0 on success - 1 on failure - """ - sub_commands = {'usage': show_usage, - 'show': do_show, - 'show-all': do_show_all, - 'sync': do_sync, - 'create': do_create, - 'destroy': do_destroy, - 'attach': do_attach, - 'detach': do_detach - } - - # global _this_instance_ocid + Return value of the operation, if any. + 0 otherwise. + """ + global _this_instance_ocid # # command line parser = get_args_parser() @@ -2775,21 +2360,311 @@ def main(): if args.command == 'usage': parser.print_help() - return 0 + sys.exit(0) + # + # try to create an oci api session + oci_sess = get_oci_api_session() + # + # get the ocid of this instance + _this_instance_ocid = get_this_instance_ocid(session=oci_sess) # - # operator needs to have root priviliges. + # set the compatibility parameters, if necessary + compatibility_mode, args.output_mode, args.details = get_compatibility_mode(args) + # + # starting from here, nothing works if we are not root if not is_root_user(): _logger.error('This program needs to be run with root privileges.') return 1 + # + # collect iscsi volume information + system_disks = lsblk.list_blk_dev() + # + # we are not touching boot volume in iscsi config + # iscsiadm_session = get_iscsiadm_session() + iscsiadm_session = iscsiadm.session() + # + # the show option + if args.command == 'show': + _ = show_volumes(oci_session=oci_sess, iscsiadm_session=iscsiadm_session, system_disks=system_disks, args=args) + return 0 + # + # the show-all option + if args.command == 'show-all': + args.all = True + # args.output_mode = 'table' + args.no_truncate = not args.truncate + args.compartments = () + args.details = True + _ = show_volumes(oci_session=oci_sess, iscsiadm_session=iscsiadm_session, system_disks=system_disks, args=args) + return 0 + # + # evaluate the number of volumes + max_volumes = get_max_volumes() + # + # load iscsiadm-cache + targets, attach_failed = load_iscsi_admin_cache() + # + # load detached volumes cache + detached_volume_iqns = load_detached_volumes_cache() + # + # the sync option + if args.command == 'sync' and not detached_volume_iqns and not attach_failed: + # nothing to do, stop here + print("All known devices are attached.") - try: - res = sub_commands[args.command](args) - if not res: - raise IscsiConfigException('Failed to complete %s.' % sub_commands[args.command].__name__) + if args.command == 'sync': + # + # we still have volume not attached, process them. + # this one is as good as obsolete, ocid takes care of executing iscsiadm attach commands. + # and detached volume iqns contains volumes which are detached from oci instance + return_value_f = 0 + synced_f = False + if detached_volume_iqns: + _logger.info("Detached devices:") + synced_d, return_value_d = sync_detached_devices(oci_sess, + detached_volume_iqns, + targets, + apply=args.apply, + interactive=args.interactive, + apply_yes=args.yes) + return_value_d = 0 + synced_d = False + if attach_failed: + _logger.info("Devices that could not be attached automatically:") + synced_f, return_value_f = sync_failed_attached(oci_sess, + attach_failed, + targets, + apply=args.apply, + interactive=args.interactive, + apply_yes=args.yes) + + if synced_d or synced_f: + _logger.debug('Trigger ocid refresh.') + # + # would be better to execute ocid_refresh anyway. + # ocid_refresh() + ocid_refresh(wait=True) + return return_value_d + return_value_f + + if args.command == 'create': + if len(system_disks) > max_volumes: + _logger.error("This instance reached the max_volumes(%s)", max_volumes) + return 1 + try: + if bool(oci_sess): + do_create_volume(oci_sess, + size=args.size, + display_name=args.volume_name, + attach_it=args.attach_volume, + detached=detached_volume_iqns, + chap_credentials=args.chap, + mode=compatibility_mode) + else: + _logger.info('Unable to create volume, failed to create a session.') + return 1 + except Exception as e: + _logger.debug('Volume creation has failed: %s', str(e), stack_info=True, exc_info=True) + _logger.error('Volume creation has failed: %s', str(e)) + return 1 + + ocid_refresh(wait=True) return 0 - except Exception as e: - _logger.error('*** ERROR *** %s', str(e)) - return 1 + + if args.command == 'destroy': + # destroy command used to be for only one volume + # changed the behavior to be more aligned with attach/dettach commands + # i.e : taking more than one ocid and doing a best effort + retval = 0 + if not args.yes: + for ocid in args.ocids: + _logger.info("Volume : [%s]", ocid) + # if not ask_yes_no("WARNING: the volume(s) will be destroyed. This is irreversible. Continue?"): + if not _read_yn('WARNING: the volume(s) will be destroyed. This is irreversible. Continue?', + yn=True, + waitenter=True, + suppose_yes=False, + default_yn=False): + return 0 + for ocid in args.ocids: + try: + if bool(oci_sess): + _logger.debug('Destroying [%s]', ocid) + # + # try to get the iqn from a detached volume + _iqn = get_iqn_from_ocid(oci_sess, ocid) + do_destroy_volume(oci_sess, ocid) + _ = remove_chap_secret(ocid) + _logger.info("Volume [%s] is destroyed", ocid) + # + # remove iqn from ignore list. + if bool(_iqn): + if _iqn in detached_volume_iqns: + detached_volume_iqns.remove(_iqn) + # write_cache(cache_content=detached_volume_iqns, cache_fname=__ignore_file) + write_cache_11876(cache_content=list(set(detached_volume_iqns)), + cache_fname=iscsiadm.IGNOREIQNS_CACHE, + cache_fname_11876=__ignore_file) + _logger.debug('%s removed from cache.', _iqn) + else: + _logger.info('Unable to destroy volume, failed to create a session.') + retval = 1 + except Exception as e: + _logger.debug('Volume [%s] deletion has failed: %s', ocid, str(e), stack_info=True, exc_info=True) + _logger.error('Volume [%s] deletion has failed: %s', ocid, str(e)) + retval = 1 + + return retval + + if args.command == 'detach': + return_value = 0 + for iqn in args.iqns: + retval = 0 + if not _wait_for_detached_cache(iqn): + _logger.error("Target [%s] is already detached", iqn) + retval = 1 + # continue + if iqn not in iscsiadm_session or 'device' not in iscsiadm_session[iqn]: + _logger.error("Target [%s] not found", iqn) + retval = 1 + # continue + if retval == 0: + _logger.debug('Unmounting the block volume') + if not unmount_device(iscsiadm_session, iqn, system_disks): + _logger.debug('Unmounting has failed') + if not args.force: + # if not ask_yes_no("Failed to unmount volume, Continue detaching anyway?"): + if not _read_yn('Failed to unmount volume, Continue detaching anyway?', + yn=True, + waitenter=True, + suppose_yes=False, + default_yn=False): + continue + else: + _logger.info('Unmount failed, force option selected,continue anyway.') + try: + if bool(oci_sess): + _logger.debug('Detaching [%s]', iqn) + do_detach_volume(oci_sess, iscsiadm_session, iqn, mode=compatibility_mode) + compat_info_message(gen_msg="Volume [%s] is detached." % iqn, mode=compatibility_mode) + detached_volume_iqns.append(iqn) + write_cache_11876(cache_content=list(set(detached_volume_iqns)), + cache_fname=iscsiadm.IGNOREIQNS_CACHE, + cache_fname_11876=__ignore_file) + else: + _logger.info('Unable to detach volume, failed to create a session.') + retval = 1 + except Exception as e: + _logger.debug('Volume [%s] detach has failed: %s', iqn, str(e), stack_info=True, exc_info=True) + _logger.error('Volume [%s] detach has failed: %s', iqn, str(e)) + retval = 1 + + if retval == 0: + # compat_info_message(gen_msg="Updating detached volume cache file: remove %s" + # % iqn, mode=compatibility_mode) + # compat_info_message(gen_msg="Volume [%s] successfully detached." % iqn, mode=compatibility_mode) + # write_cache(cache_content=detached_volume_iqns, cache_fname=__ignore_file) + # __GT__ + pass + # write_cache_11876(cache_content=list(set(detached_volume_iqns)), + # cache_fname=iscsiadm.IGNOREIQNS_CACHE, + # cache_fname_11876=__ignore_file) + else: + return_value = retval + _logger.debug('Trigger ocid refresh') + ocid_refresh(wait=True) + return return_value + + if args.command == 'attach': + if len(system_disks) > max_volumes: + _logger.error("This instance reached the maximum number of volumes attached (%s)", max_volumes) + return 1 + + if bool(args.ocids): + iqnocid = args.ocids + elif bool(args.iqns): + iqnocid = args.iqns + else: + # should be trapped by argparse, one of those is required. + _logger.error('Missing iqns or ocids') + sys.exit(1) + + retval = 0 + for iqnorocid in iqnocid: + _save_chap_cred = False + if iqnorocid in iscsiadm_session: + _logger.info("Target [%s] is already attached.", iqnorocid) + continue + + if iqnorocid.startswith(oci_volume_tag): + # + # ocid + _logger.debug('Given IQN [%s] is probably an ocid, attaching it', iqnorocid) + + attach_data = do_oci_vol_attach_ocid(oci_sess, compatibility_mode, iqnorocid, args.chap) + if not bool(attach_data): + retval = 1 + continue + elif iqnorocid.startswith(iqn_tag): + # + # iqn + _logger.debug('Given IQN [%s] is probably an iqn, attaching it', iqnorocid) + + attach_data = do_oci_vol_attach_iqn(oci_sess, iscsiadm_session, iqnorocid, args.username, args.password) + if not bool(attach_data): + retval = 1 + continue + else: + # + # invalid parameter + _logger.info('Invalid argument, given IQN [%s] is not an iqn nor an ocid.', iqnorocid) + retval = 1 + continue + # + _logger.debug('Attaching [%s] to iSCSI session', iqnorocid) + try: + _do_iscsiadm_attach(attach_data['iqn_to_use'], + targets, + user=attach_data['attachment_username'], + passwd=attach_data['attachment_password'], + iscsi_portal_ip=attach_data['iscsi_portal_ip']) + _logger.debug('Attachment of %s succeeded.', iqnorocid) + if attach_data['iqn_to_use'] in detached_volume_iqns: + _logger.debug('Volume %s was detached, remove from detached list.', iqnorocid) + detached_volume_iqns.remove(attach_data['iqn_to_use']) + write_cache_11876(cache_content=list(set(detached_volume_iqns)), + cache_fname=iscsiadm.IGNOREIQNS_CACHE, + cache_fname_11876=__ignore_file) + # __GT__ + # if _save_chap_cred: + if args.chap: + _logger.debug('Attachment OK: saving chap credentials.') + add_chap_secret(iqnorocid, attach_data['attachment_username'], attach_data['attachment_password']) + except Exception as e: + _logger.debug("Failed to attach target [%s]: %s", iqnorocid, str(e), exc_info=True, stack_info=True) + _logger.error("Failed to attach target [%s]: %s", iqnorocid, str(e)) + _save_chap_cred = False + retval = 1 + continue + + if retval == 0: + # + # update the detached volumes cache + # write_cache(cache_content=detached_volume_iqns, cache_fname=__ignore_file) + # write_cache_11876(cache_content=list(set(detached_volume_iqns)), + # cache_fname=iscsiadm.IGNOREIQNS_CACHE, + # cache_fname_11876=__ignore_file) + # + # run ocid.refresh + _logger.debug('Trigger ocid refresh.') + ocid_refresh(wait=True) + + return retval + + if not attach_failed and not detached_volume_iqns: + print("All known devices are attached.") + print("Use the show (or -s, --show) option for details.") + + return 0 if __name__ == "__main__": diff --git a/lib/oci_utils/impl/oci_network_config_main.py b/lib/oci_utils/impl/oci_network_config_main.py index 8a47db3f..13098c7b 100644 --- a/lib/oci_utils/impl/oci_network_config_main.py +++ b/lib/oci_utils/impl/oci_network_config_main.py @@ -23,6 +23,7 @@ from oci_utils.impl.oci_resources import OCIVNIC from oci_utils.impl.row_printer import TablePrinter from oci_utils.impl.row_printer import TextPrinter +from oci_utils.impl.row_printer import get_row_printer_impl from oci_utils.impl.row_printer_helpers import IndentPrinter from oci_utils.impl.row_printer_helpers import get_value_data from oci_utils.impl.row_printer_helpers import initialise_column_lengths @@ -37,34 +38,6 @@ VNIC_PREFIX = ['ocid1.vnic.oc'] -class NetworkConfigException(Exception): - """Class of exceptions during notification handling - """ - def __init__(self, message=None): - """ - Initialisation of the Oci NetworkConfig Exception. - - Parameters - ---------- - message: str - The exception message. - """ - super().__init__() - self._message = message - assert (self._message is not None), 'No exception message given, no further information.' - - def __str__(self): - """ - Get this OCISDKError representation. - - Returns - ------- - str - The error message. - """ - return str(self._message) - - class NameWithSpaces(argparse.Action): """ Handle argparse arguments containing spaces. """ @@ -462,7 +435,12 @@ def def_add_secondary_addr_parser(s_parser): add_secondary_addr = s_parser.add_parser('add-secondary-addr', description="Adds the given secondary private IP.", help="Adds the given secondary private IP.") - + # add_secondary_addr.add_argument('--ipv', + # action='store', + # type=int, + # choices=[4, 6], + # default=4, + # help='Add an ipv4 or ipv6 address.') ipv = add_secondary_addr.add_mutually_exclusive_group() ipv.add_argument('-ipv4', '--ipv4', action='store_true', @@ -565,23 +543,6 @@ def get_arg_parser(): return parser -def show_usage(usage_args): - """ - Wrapper for showing usage info. - - Parameters - ---------- - usage_args: - The command line arguments. - - Returns - ------- - bool: True on success, False otherwise. - """ - _logger.debug('%s', where_am_i()) - return True - - def uniq_item_validator(value): """ Validates unicity by checking that value not already in the list @@ -723,31 +684,6 @@ def ip_address_validator(value): raise argparse.ArgumentTypeError('Invalid arguments: %s is not a valid IP address.' % value) -def get_conf_states(vnics): - """ - Get configuration state of the vnic, - - Parameters - ---------- - vnics: OCIVNIC - The OCIVNIC object. - - Returns - ------- - dict: The configuration states. - """ - _logger.debug('%s', where_am_i()) - _network_config = VNICUtils().get_network_config() - conf_states = dict() - for vnic in vnics: - priv_ip = vnic.get_private_ip() - for network in _network_config: - if priv_ip == network['ADDR']: - conf_states[priv_ip] = network['CONFSTATE'] - break - return conf_states - - def get_oci_api_session(): """ Ensure the OCI SDK is available if the option is not None. @@ -767,7 +703,7 @@ def get_oci_api_session(): _logger.debug('Creating session') sess = oci_utils.oci_api.OCISession() # it seems that having a client is not enough, we may not be able to query anything on it - # work around but not full-proof: + # workaround : # try a dummy call to be sure that we can use this session if not bool(sess.this_instance()): _logger.debug('Returning None session') @@ -779,114 +715,71 @@ def get_oci_api_session(): return sess -def compat_show_vnics_information(): +def show_vcn(args): """ - Show the current VNIC configuration of the instance based on + Show virtual cloud network data. + + Parameters + ---------- + args: namespace + The command line. Returns ------- - No return value. + No return value. """ - def _display_subnet(_, vn): - """Return subnet display name of this vnic - """ - return vn.get_subnet().get_display_name() - - def _display_secondary_ip_subnet(_, privip): - _sn = privip.get_subnet() - return '%s (%s)' % (_sn.get_display_name(), _sn.get_ipv4_cidr_block()) - - def _display_vnic_name(_, vn): - return '%s (primary)' % vn.get_display_name() if vn.is_primary() else vn.get_display_name() - _logger.debug('%s', where_am_i()) - oci_session = get_oci_api_session() - if oci_session is None: + sess = get_oci_api_session() + if sess is None: _logger.error("Failed to get API session.") - return - instance = oci_session.this_instance() - if instance is None: - _logger.error("Failed to get information from OCI.") - return - _logger.debug('Getting all vnics ') - vnics = instance.all_vnics() - _logger.debug('Got all vnics for printing') - - _title = 'VNIC configuration for instance %s:' % instance.get_display_name() - - _columns = (['Name', 32, _display_vnic_name], - ['Hostname', 25, 'get_hostname'], - ['MAC', 17, 'get_mac_address'], - ['Public IP', 15, 'get_public_ip'], - ['Private IP(s)', 15, 'get_private_ip'], - ['Subnet', 18, _display_subnet], - ['OCID', 90, 'get_ocid']) - - printer = TextPrinter(title=_title, columns=_columns, column_separator=' ') - ips_printer = TextPrinter(title='Private IP addresses:', - columns=(['IP address', 15, 'get_address'], - ['OCID', '90', 'get_ocid'], - ['Hostname', 25, 'get_hostname'], - ['Subnet', 24, _display_secondary_ip_subnet]), - printer=IndentPrinter(3)) - - printer.printHeader() - for vnic in vnics: - printer.printRow(vnic) - # - # to check if compatible mode works with ipv6 as soon as primary ipv6 address for a vnic and/or single stack - # ipv6 is implemented on OCI and oci sdk: - _all_p_ips = vnic.all_private_ips() - if len(_all_p_ips) > 1: - # _all_p_ips include the primary we won't print (>1) - ips_printer.printHeader() - for p_ip in _all_p_ips: - if not p_ip.is_primary(): - # primary already displayed - ips_printer.printRow(p_ip) - printer.rowBreak() - ips_printer.printFooter() - ips_printer.finish() - printer.printFooter() - printer.finish() + return 1 + vcns = set() + _vcns = sess.all_vcns() + if not args.ocid and not args.name: + vcns.update(_vcns) + else: + if args.ocid: + for v in _vcns: + if v.get_ocid() == args.ocid: + vcns.add(v) + if args.name: + for v in _vcns: + if v.get_display_name() == args.name: + vcns.add(v) + do_show_vcn_information(vcns, args) + return 0 -def do_show_information(nic_list, args): +def do_show_vcn_information(vcn_list, args): """ - Show network information. + Display virtual cloud network data. Parameters ---------- - nic_list: - list: list of network data. + vcn_list: list of OCIVCN + The list of vnics. args: namespace - The command line. + The command line arguments. Returns ------- No return value. """ _logger.debug('%s', where_am_i()) + # + # _data_struct = { - 'state': {'head': 'State', 'item': 'CONFSTATE', 'type': 'str', 'collen': 6}, - 'link': {'head': 'Link', 'item': 'IFACE', 'type': 'str', 'collen': 5}, - 'status': {'head': 'Status', 'item': 'STATE', 'type': 'str', 'collen': 6}, - 'ipaddress': {'head': 'IP address', 'item': 'ADDR', 'type': 'str', 'collen': 9}, - 'vnic': {'head': 'VNIC', 'item': 'VNICNAME', 'type': 'str', 'collen': 6}, - 'mac': {'head': 'MAC', 'item': 'MAC', 'type': 'str', 'collen': 17} + 'name': {'head': 'Name', 'func': 'get_display_name', 'type': 'str', 'collen': 20}, + 'ipv4': {'head': 'IPv4 cidr block', 'func': 'get_ipv4_cidr_block', 'type': 'str', 'collen': 15}, + 'ipv6': {'head': 'IPv6 cidr block', 'func': 'get_ipv6_cidr_blocks', 'type': 'str', 'collen': 20, 'convert': list_to_str} } _data_struct_detail = { - 'hostname': {'head': 'Hostname', 'item': 'HOSTNAME', 'type': 'str', 'collen': 8}, - 'subnet': {'head': 'Subnet', 'item': 'SUBNET', 'type': 'str', 'collen': 10}, - 'routerip': {'head': 'Router IPv4', 'item': 'VIRTRT4', 'type': 'str', 'collen': 9}, - 'routerip6': {'head': 'Router IPv6', 'item': 'VIRTRT6', 'type': 'str', 'collen': 9}, - 'namespace': {'head': 'Namespace', 'item': 'NS', 'type': 'str', 'collen': 9}, - 'index': {'head': 'Index', 'item': 'IND', 'type': 'str', 'collen': 5}, - 'vlantag': {'head': 'VLAN tag', 'item': 'VLTAG', 'type': 'str', 'collen': 8}, - 'vlan': {'head': 'VLAN', 'item': 'VLAN', 'type': 'str', 'collen': 4} + 'uuid': {'head': 'OCID', 'func': 'get_ocid', 'type': 'str', 'collen': 32}, + 'ipv4s': {'head': 'IPv4 cidr blocks', 'func': 'get_ipv4_cidr_blocks', 'type': 'str', 'collen': 16, 'convert': list_to_str}, + 'dns': {'head': 'DNS label', 'func': 'get_dns_label', 'type': 'str', 'collen': 10}, + 'state': {'head': 'State', 'func': 'get_state', 'type': 'str', 'collen': 10}, + 'life ': {'head': 'Lifecycle state', 'func': 'get_lifecycle_state', 'type': 'str', 'collen': 17} } - # - # add details information if args.details: _data_struct.update(_data_struct_detail) # @@ -894,189 +787,181 @@ def do_show_information(nic_list, args): if args.no_truncate: _data_struct = initialise_column_lengths(_data_struct) # - nic_data = list() - for _nic in nic_list: - _nic_dict = dict() + vcn_data = list() + for _vcn in vcn_list: + _vcn_dict = dict() for key, _ in _data_struct.items(): - value_data = get_value_data(_nic, _data_struct[key]) - _nic_dict[key] = value_data[0] + value_data = get_value_data(_vcn, _data_struct[key]) + _vcn_dict[key] = value_data[0] val_length = value_data[1] if args.no_truncate: _data_struct[key]['collen'] = max(val_length, _data_struct[key]['collen']) - nic_data.append(_nic_dict) + vcn_data.append(_vcn_dict) # - print_data('Network Configuration', + print_data('Virtual Cloud Network Information:', _data_struct, - nic_data, + vcn_data, mode=args.output_mode, truncate=not args.no_truncate) - return True -def update_network_config(nw_conf): +def show_subnet(args): """ - Add data from vnic to the network data. + Show virtual cloud subnet data. Parameters ---------- - nw_conf: list - List of network configuration data. + args: namespace + The command line. Returns ------- - list: list of updated network configuration data. + No return value. """ - def _get_vnic_name(interface): - """ - Get the vnic name. - - Parameters - ---------- - interface: dict - The interface. - - Returns - ------- - str: the vnic name if the interface matches a vnic, else '-' - """ - _logger.debug('%s', where_am_i()) - if interface['VNIC']: - for v in vnics: - if v.get_ocid() == interface['VNIC']: - return v.get_display_name() - return '-' - - def _get_hostname(interface): - """ - Return the interfaces' hostname. - - Parameters - ---------- - interface: dict - The interface. - - Returns - ------- - str: the vnic hostname if the interface matches a vnic, else '-' - """ - _logger.debug('%s', where_am_i()) - if interface['VNIC']: - for v in vnics: - if v.get_ocid() == interface['VNIC']: - v_hostname = v.get_hostname() - return 'None' if v_hostname is None else v_hostname - return '-' - - def _display_subnet(interface): - """ - Return the network subnet. - - Parameters - ---------- - interface: dict - The interface. - - Returns - ------- - str: the network subnet or if the interface matches a vnic, the OCI vnic subnet. - """ - _logger.debug('%s', where_am_i()) - if interface['VNIC']: - for v in vnics: - if v.get_ocid() == interface['VNIC']: - v_subnet = [interface['SPREFIX4'], interface['SBITS4']] - return '%s/%s (%s)' % (v_subnet[0], v_subnet[1], v.get_subnet().get_display_name()) - return '%s/%s' % (interface['SPREFIX4'], interface['SBITS4']) - _logger.debug('%s', where_am_i()) sess = get_oci_api_session() if sess is None: - raise Exception("Failed to get API session.") - vnics = sess.this_instance().all_vnics() - - for _nic in nw_conf: - _nic['VNICNAME'] = _get_vnic_name(_nic) - _nic['HOSTNAME'] = _get_hostname(_nic) - _nic['SUBNET'] = _display_subnet(_nic) - return nw_conf + _logger.error("Failed to get API session.") + return 1 + subnets = set() + _subnets = sess.all_subnets() + if not args.ocid and not args.name: + subnets.update(_subnets) + else: + if args.ocid: + for s in _subnets: + if s.get_ocid() == args.ocid: + subnets.add(s) + if args.name: + for s in _subnets: + if s.get_display_name() == args.name: + subnets.add(s) + do_show_subnet_information(subnets, args) + return 0 -def show_os_network_config(vnic_utils): +def do_show_subnet_information(subnet_list, args): """ - Display the current network interface configuration as well as the VNIC configuration from OCI. + Display subnetdata. Parameters ---------- - vnic_utils : - The VNIC configuration instance. + subnet_list: list of OCISubnet + The list of subnets. + args: namespace + The command line. Returns ------- No return value. """ - def _get_subnet(_, interface): - return '%s/%s' % (interface['SPREFIX4'], interface['SBITS4']) - _logger.debug('%s', where_am_i()) - ret = vnic_utils.get_network_config() - - _title = "Operating System level network configuration:" - _columns = (['CONFIG', 6, 'CONFSTATE'], - ['ADDR', 15, 'ADDR'], - ['SUBNET', 15, 'SPREFIX4'], - ['BITS', 5, 'SBITS4'], - ['VIRTROUTER', 15, 'VIRTRT4'], - ['NS', 10, 'NS'], - ['IND', 4, 'IND'], - ['IFACE', 15, 'IFACE'], - ['VLTAG', 5, 'VLTAG'], - ['VLAN', 13, 'VLAN'], - ['STATE', 6, 'STATE'], - ['MAC', 18, 'MAC'], - ['VNIC ID', 95, 'VNIC']) - printer = TablePrinter(title=_title, columns=_columns, column_separator=' ', text_truncate=False) - - printer.printHeader() - for item in ret: - printer.printRow(item) - printer.printFooter() - printer.finish() + # + # + _data_struct = { + 'name': {'head': 'Name', 'func': 'get_display_name', 'type': 'str', 'collen': 20}, + 'ipv4': {'head': 'ipv4 cidr block', 'func': 'get_ipv4_cidr_block', 'type': 'str', 'collen': 15}, + 'ipv6': {'head': 'ipv6 cidr block', 'func': 'get_ipv6_cidr_block', 'type': 'str', 'collen': 20} + } + _data_struct_detail = { + 'uuid': {'head': 'OCID', 'func': 'get_ocid', 'type': 'str', 'collen': 32}, + 'vcn': {'head': 'VCN name', 'func': 'get_vcn_name', 'type': 'str', 'collen': 20}, + 'vcnid': {'head': 'VCN ocid', 'func': 'get_vcn_id', 'type': 'str', 'collen': 32}, + 'public': {'head': 'Public', 'func': 'is_public_ip_on_vnic_allowed', 'type': 'bool', 'collen': 6}, + 'publicin': {'head': 'Public ingress', 'func': 'is_internet_ingress_on_vnic_allowed', 'type': 'bool', 'collen': 14}, + 'dns': {'head': 'DNS label', 'func': 'get_dns_label', 'type': 'str', 'collen': 11}, + 'domain': {'head': 'Domain name', 'func': 'get_domain_name', 'type': 'str', 'collen': 20}, + 'life ': {'head': 'Lifecycle state', 'func': 'get_lifecycle_state', 'type': 'str', 'collen': 17} + } + # + # remove vcn uuid if output mode is table + if args.output_mode in ['table']: + _data_struct_detail.pop('vcnid', None) + # + # add details if necessary + if args.details: + _data_struct.update(_data_struct_detail) + # + # initialise the column widths + if args.no_truncate: + _data_struct = initialise_column_lengths(_data_struct) + # + subnet_data = list() + for _subn in subnet_list: + _subn_dict = dict() + for key, _ in _data_struct.items(): + value_data = get_value_data(_subn, _data_struct[key]) + _subn_dict[key] = value_data[0] + val_length = value_data[1] + if args.no_truncate: + _data_struct[key]['collen'] = max(val_length, _data_struct[key]['collen']) + subnet_data.append(_subn_dict) + # + print_data('Subnet Information:', _data_struct, subnet_data, mode=args.output_mode, truncate=not args.no_truncate) -def show_network(show_args): +def show_vnics(args): """ - Display the network information. + Show Virtual Network Interface data. Parameters ---------- - show_args: namespace - The command line arguments. + args: namespace + The command line. Returns ------- - int: 0 on success, 1 otherwise. + No return value. """ _logger.debug('%s', where_am_i()) - vnic_utils = get_vnic_utils(show_args) - - network_config = vnic_utils.get_network_config() - network_config = update_network_config(network_config) - # - # for compatibility mode, oci-network-config show should provide the same output as oci-network-config --show; - # if output-mode is specified, compatiblity requirement is dropped. - showerror = False - if show_args.compat_output: - compat_show_vnics_information() + sess = get_oci_api_session() + if sess is None: + _logger.error("Failed to get API session.") + return 1 + vnics = set() + _vnics = sess.this_instance().all_vnics() + if not args.ocid and not args.name and not args.ip_address: + vnics.update(_vnics) else: - try: - do_show_information(network_config, show_args) - except Exception as e: - _logger.debug('Cannot show information', exc_info=True) - _logger.error('Cannot show information: %s', str(e)) - showerror = True - if show_args.output_mode == 'table': - show_os_network_config(vnic_utils) - return False if showerror else True + if args.ocid: + for v in _vnics: + if v.get_ocid() == args.ocid: + vnics.add(v) + if args.name: + for v in _vnics: + if v.get_display_name() == args.name: + vnics.add(v) + if args.ip_address: + for v in _vnics: + if v.get_private_ip() == args.ip_address: + vnics.add(v) + do_show_vnics_information(vnics, args) + return 0 + + +def get_conf_states(vnics): + """ + Get configuration state of the vnic, + + Parameters + ---------- + vnics: OCIVNIC + The OCIVNIC object. + + Returns + ------- + dict: The configuration states. + """ + _logger.debug('%s', where_am_i()) + _network_config = VNICUtils().get_network_config() + conf_states = dict() + for vnic in vnics: + priv_ip = vnic.get_private_ip() + for network in _network_config: + if priv_ip == network['ADDR']: + conf_states[priv_ip] = network['CONFSTATE'] + break + return conf_states def do_show_vnics_information(vnics, args): @@ -1085,9 +970,9 @@ def do_show_vnics_information(vnics, args): Parameters: ---------- - vnics: OCIVNIC instances - mode: the output mode as str (text,json,parsable) - details: display detailed information ? + vnics : OCIVNIC instances + mode : the output mode as str (text,json,parsable) + details : display detailed information ? """ _logger.debug('%s', where_am_i()) _data_struct = { @@ -1113,12 +998,10 @@ def do_show_vnics_information(vnics, args): 'privateip': {'head': 'Private IP', 'func': 'get_address', 'type': 'str', 'collen': 15}, 'ocid': {'head': 'OCID', 'func': 'get_ocid', 'type': 'str', 'collen': 32}, } - # # remove vcn uuid if output mode is table if args.output_mode in ['table']: _data_struct_detail.pop('subnetid', None) - # - # add details information + if args.details: _data_struct.update(_data_struct_detail) # @@ -1184,297 +1067,323 @@ def do_show_vnics_information(vnics, args): truncate=not args.no_truncate) -def show_vnics(args): +def do_show_information(vnic_utils, mode, details=False): """ - Show Virtual Network Interface data. + Display network information Parameters ---------- - args: namespace - The command line. + vnic_utils : instance of VNICUtils - Returns - ------- - No return value. + mode : str + output mode (text,parsable etc...) + details : bool + display detailed information ? """ _logger.debug('%s', where_am_i()) sess = get_oci_api_session() if sess is None: - _logger.error("Failed to get API session.") - return 1 - vnics = set() - _vnics = sess.this_instance().all_vnics() - if not args.ocid and not args.name and not args.ip_address: - vnics.update(_vnics) - else: - if args.ocid: - for v in _vnics: - if v.get_ocid() == args.ocid: - vnics.add(v) - if args.name: - for v in _vnics: - if v.get_display_name() == args.name: - vnics.add(v) - if args.ip_address: - for v in _vnics: - if v.get_private_ip() == args.ip_address: - vnics.add(v) - do_show_vnics_information(vnics, args) - return True + raise Exception("Failed to get API session.") + vnics = sess.this_instance().all_vnics() + network_config = vnic_utils.get_network_config() -def show_vnics_all(args): - """ - Show all Virtual Network Interface data. + def _display_subnet(interface): + """ + Return the network subnet. - Parameters - ---------- - args: namespace - The command line. + Parameters + ---------- + interface: dict + The interface. + + Returns + ------- + str: the network subnet or if the interface matches a vnic, the OCI vnic subnet. + """ + _logger.debug('%s', where_am_i()) + if interface['VNIC']: + for v in vnics: + if v.get_ocid() == interface['VNIC']: + v_subnet = [interface['SPREFIX4'], interface['SBITS4']] + return '%s/%s (%s)' % (v_subnet[0], v_subnet[1], v.get_subnet().get_display_name()) + return '%s/%s' % (interface['SPREFIX4'], interface['SBITS4']) + + def _get_vnic_name(interface): + """ + Get the vnic name. + + Parameters + ---------- + interface: dict + The interface. + + Returns + ------- + str: the vnic name if the interface matches a vnic, else '-' + """ + _logger.debug('%s', where_am_i()) + if interface['VNIC']: + for v in vnics: + if v.get_ocid() == interface['VNIC']: + return v.get_display_name() + return '-' + + def _get_hostname(interface): + """ + Return the interfaces' hostname. + + Parameters + ---------- + interface: dict + The interface. + + Returns + ------- + str: the vnic hostname if the interface matches a vnic, else '-' + """ + _logger.debug('%s', where_am_i()) + if interface['VNIC']: + for v in vnics: + if v.get_ocid() == interface['VNIC']: + v_hostname = v.get_hostname() + return 'None' if v_hostname is None else v_hostname + return '-' - Returns - ------- - No return value. - """ _logger.debug('%s', where_am_i()) - args.no_truncate = True - args.details = True - args.ocid = None - args.ip_address = None - args.name = None - return show_vnics(args) + _cols = ['State', 'Link', 'Status', 'IP address', 'VNIC', 'MAC'] + _col_name = ['state', 'link', 'status', 'ipaddress', 'vnic', 'mac'] + _cols_details = ['Hostname', 'Subnet', 'Router IP', 'Namespace', 'Index', 'VLAN tag', 'VLAN'] + _col_detail_name = ['hostname', 'subnet', 'routerip4', 'namespace', 'index', 'vlantag', 'vlan'] + if details: + _cols = [*_cols, *_cols_details] + _col_name = [*_col_name, *_col_detail_name] -def do_show_vcn_information(vcn_list, args): - """ - Display virtual cloud network data. + _cols_len = list() + for col in _cols: + _cols_len.append(len(col)) + _collen = dict(zip(_col_name, _cols_len)) - Parameters - ---------- - vcn_list: list of OCIVCN - The list of vnics. - args: namespace - The command line arguments. + vnic_data = list() + for item in network_config: + _nic_data = dict() + # state + _nic_data['state'] = item['CONFSTATE'] + _collen['state'] = max(len(_nic_data['state']), _collen['state']) + # link + _nic_data['link'] = item['IFACE'] + _collen['link'] = max(len(_nic_data['link']), _collen['link']) + # status + _nic_data['status'] = item['STATE'] + _collen['status'] = max(len(_nic_data['status']), _collen['status']) + # ipaddress + _nic_data['ipaddress'] = item['ADDR'] + _collen['ipaddress'] = max(len(_nic_data['ipaddress']), _collen['ipaddress']) + # vnic + _nic_data['vnic'] = _get_vnic_name(item) + _collen['vnic'] = max(len(_nic_data['vnic']), _collen['vnic']) + # mac + _nic_data['mac'] = item['MAC'] + _collen['mac'] = max(len(_nic_data['mac']), _collen['mac']) + if details: + # hostname + _nic_data['hostname'] = _get_hostname(item) + _collen['hostname'] = max(len(_nic_data['hostname']), _collen['hostname']) + # subnet + _nic_data['subnet'] = _display_subnet(item) + _collen['subnet'] = max(len(_nic_data['subnet']), _collen['subnet']) + # routerip4 + _nic_data['routerip4'] = item['VIRTRT4'] + _collen['routerip4'] = max(len(_nic_data['routerip4']), _collen['routerip4']) + # namespace + _nic_data['namespace'] = item['NS'] + _collen['namespace'] = max(len(_nic_data['namespace']), _collen['namespace']) + # index + _nic_data['index'] = item['IND'] + _collen['index'] = max(len(_nic_data['index']), _collen['index']) + # vlantag + _nic_data['vlantag'] = item['VLTAG'] + _collen['vlantag'] = max(len(_nic_data['vlantag']), _collen['vlantag']) + # vlan + _nic_data['vlan'] = item['VLAN'] + _collen['vlan'] = max(len(_nic_data['vlan']), _collen['vlan']) + vnic_data.append(_nic_data) + + _columns = list() + for i, _ in enumerate(_cols): + _columns.append([_cols[i], _collen[_col_name[i]]+2, _col_name[i]]) + + printerKlass = get_row_printer_impl(mode) + printer = printerKlass(title='Network configuration', columns=_columns) + + printer.printHeader() + for item in vnic_data: + printer.printRow(item) + printer.rowBreak() + printer.printFooter() + printer.finish() + + +def compat_show_vnics_information(): + """ + Show the current VNIC configuration of the instance based on Returns ------- - No return value. + No return value. """ _logger.debug('%s', where_am_i()) - # - # - _data_struct = { - 'name': {'head': 'Name', 'func': 'get_display_name', 'type': 'str', 'collen': 20}, - 'ipv4': {'head': 'IPv4 cidr block', 'func': 'get_ipv4_cidr_block', 'type': 'str', 'collen': 15}, - 'ipv6': {'head': 'IPv6 cidr block', 'func': 'get_ipv6_cidr_blocks', 'type': 'str', 'collen': 20, 'convert': list_to_str} - } - _data_struct_detail = { - 'uuid': {'head': 'OCID', 'func': 'get_ocid', 'type': 'str', 'collen': 32}, - 'ipv4s': {'head': 'IPv4 cidr blocks', 'func': 'get_ipv4_cidr_blocks', 'type': 'str', 'collen': 16, 'convert': list_to_str}, - 'dns': {'head': 'DNS label', 'func': 'get_dns_label', 'type': 'str', 'collen': 10}, - 'state': {'head': 'State', 'func': 'get_state', 'type': 'str', 'collen': 10}, - 'life ': {'head': 'Lifecycle state', 'func': 'get_lifecycle_state', 'type': 'str', 'collen': 17} - } - # - # add details if requested. - if args.details: - _data_struct.update(_data_struct_detail) - # - # initialise the column widths if no-truncate is set - if args.no_truncate: - _data_struct = initialise_column_lengths(_data_struct) - # - vcn_data = list() - for _vcn in vcn_list: - _vcn_dict = dict() - for key, _ in _data_struct.items(): - value_data = get_value_data(_vcn, _data_struct[key]) - _vcn_dict[key] = value_data[0] - val_length = value_data[1] - if args.no_truncate: - _data_struct[key]['collen'] = max(val_length, _data_struct[key]['collen']) - vcn_data.append(_vcn_dict) - # - print_data('Virtual Cloud Network Information:', - _data_struct, - vcn_data, - mode=args.output_mode, - truncate=not args.no_truncate) + def _display_subnet(_, vn): + """Return subnet display name of this vnic + """ + return vn.get_subnet().get_display_name() -def show_vcns(args): - """ - Show virtual cloud network data. + def _display_secondary_ip_subnet(_, privip): + _sn = privip.get_subnet() + return '%s (%s)' % (_sn.get_display_name(), _sn.get_ipv4_cidr_block()) - Parameters - ---------- - args: namespace - The command line. + def _display_vnic_name(_, vn): + if vn.is_primary(): + return '%s (primary)' % vn.get_display_name() + return vn.get_display_name() - Returns - ------- - No return value. - """ _logger.debug('%s', where_am_i()) sess = get_oci_api_session() if sess is None: _logger.error("Failed to get API session.") - return 1 - vcns = set() - _vcns = sess.all_vcns() - if not args.ocid and not args.name: - vcns.update(_vcns) - else: - if args.ocid: - for v in _vcns: - if v.get_ocid() == args.ocid: - vcns.add(v) - if args.name: - for v in _vcns: - if v.get_display_name() == args.name: - vcns.add(v) - do_show_vcn_information(vcns, args) - return True + return + _logger.debug('Getting instance ') + inst = sess.this_instance() + if inst is None: + _logger.error("Failed to get information from OCI.") + return + _logger.debug('Getting all vnics ') + vnics = inst.all_vnics() + _logger.debug('Got for printing') + _title = 'VNIC configuration for instance %s:' % inst.get_display_name() -def do_show_subnet_information(subnet_list, args): - """ - Display subnetdata. + _columns = (['Name', 32, _display_vnic_name], + ['Hostname', 25, 'get_hostname'], + ['MAC', 17, 'get_mac_address'], + ['Public IP', 15, 'get_public_ip'], + ['Private IP(s)', 15, 'get_private_ip'], + ['Subnet', 18, _display_subnet], + ['OCID', 90, 'get_ocid']) - Parameters - ---------- - subnet_list: list of OCISubnet - The list of subnets. - args: namespace - The command line. + printer = TextPrinter(title=_title, columns=_columns, column_separator='') + ips_printer = TextPrinter(title='Private IP addresses:', + columns=(['IP address', 15, 'get_address'], + ['OCID', '90', 'get_ocid'], + ['Hostname', 25, 'get_hostname'], + ['Subnet', 24, _display_secondary_ip_subnet]), + printer=IndentPrinter(3)) - Returns - ------- - No return value. - """ - _logger.debug('%s', where_am_i()) - # - # - _data_struct = { - 'name': {'head': 'Name', 'func': 'get_display_name', 'type': 'str', 'collen': 20}, - 'ipv4': {'head': 'ipv4 cidr block', 'func': 'get_ipv4_cidr_block', 'type': 'str', 'collen': 15}, - 'ipv6': {'head': 'ipv6 cidr block', 'func': 'get_ipv6_cidr_block', 'type': 'str', 'collen': 20} - } - _data_struct_detail = { - 'uuid': {'head': 'OCID', 'func': 'get_ocid', 'type': 'str', 'collen': 32}, - 'vcn': {'head': 'VCN name', 'func': 'get_vcn_name', 'type': 'str', 'collen': 20}, - 'vcnid': {'head': 'VCN ocid', 'func': 'get_vcn_id', 'type': 'str', 'collen': 32}, - 'public': {'head': 'Public', 'func': 'is_public_ip_on_vnic_allowed', 'type': 'bool', 'collen': 6}, - 'publicin': {'head': 'Public ingress', 'func': 'is_internet_ingress_on_vnic_allowed', 'type': 'bool', 'collen': 14}, - 'dns': {'head': 'DNS label', 'func': 'get_dns_label', 'type': 'str', 'collen': 11}, - 'domain': {'head': 'Domain name', 'func': 'get_domain_name', 'type': 'str', 'collen': 20}, - 'life ': {'head': 'Lifecycle state', 'func': 'get_lifecycle_state', 'type': 'str', 'collen': 17} - } - # - # remove vcn uuid if output mode is table - if args.output_mode in ['table']: - _data_struct_detail.pop('vcnid', None) - # - # add details if necessary - if args.details: - _data_struct.update(_data_struct_detail) - # - # initialise the column widths - if args.no_truncate: - _data_struct = initialise_column_lengths(_data_struct) - # - subnet_data = list() - for _subn in subnet_list: - _subn_dict = dict() - for key, _ in _data_struct.items(): - value_data = get_value_data(_subn, _data_struct[key]) - _subn_dict[key] = value_data[0] - val_length = value_data[1] - if args.no_truncate: - _data_struct[key]['collen'] = max(val_length, _data_struct[key]['collen']) - subnet_data.append(_subn_dict) - # - print_data('Subnet Information:', _data_struct, subnet_data, mode=args.output_mode, truncate=not args.no_truncate) + printer.printHeader() + for vnic in vnics: + printer.printRow(vnic) + # + # __GT__ to check if compatible mode works with ipv6: + # --> no for now, the IPv6 oci-sdk object has no attribute 'is_primary' and a few more. + _all_p_ips = vnic.all_private_ips() + if len(_all_p_ips) > 1: + # _all_p_ips include the primary we won't print (>1) + ips_printer.printHeader() + for p_ip in _all_p_ips: + if not p_ip.is_primary(): + # primary already displayed + ips_printer.printRow(p_ip) + printer.rowBreak() + ips_printer.printFooter() + ips_printer.finish() + printer.printFooter() + printer.finish() -def show_subnets(args): +def show_os_network_config(vnic_utils): """ - Show virtual cloud subnet data. + Display the current network interface configuration as well as the VNIC configuration from OCI. Parameters ---------- - args: namespace - The command line. + vnic_utils : + The VNIC configuration instance. Returns ------- No return value. """ - _logger.debug('%s', where_am_i()) - sess = get_oci_api_session() - if sess is None: - _logger.error("Failed to get API session.") - return 1 - subnets = set() - _subnets = sess.all_subnets() - if not args.ocid and not args.name: - subnets.update(_subnets) - else: - if args.ocid: - for s in _subnets: - if s.get_ocid() == args.ocid: - subnets.add(s) - if args.name: - for s in _subnets: - if s.get_display_name() == args.name: - subnets.add(s) - do_show_subnet_information(subnets, args) - return True + def _get_subnet(_, interface): + return '%s/%s' % (interface['SPREFIX4'], interface['SBITS4']) + _logger.debug('%s', where_am_i()) + ret = vnic_utils.get_network_config() -def get_ipv_version(args): - """ - Get the ip version from the commandline, default is 4. + _title = "Operating System level network configuration:" + _columns = (['CONFIG', 6, 'CONFSTATE'], + ['ADDR', 15, 'ADDR'], + ['SUBNET', 15, 'SPREFIX4'], + ['BITS', 5, 'SBITS4'], + ['VIRTROUTER', 15, 'VIRTRT4'], + ['NS', 10, 'NS'], + ['IND', 4, 'IND'], + ['IFACE', 15, 'IFACE'], + ['VLTAG', 5, 'VLTAG'], + ['VLAN', 13, 'VLAN'], + ['STATE', 6, 'STATE'], + ['MAC', 17, 'MAC'], + ['VNIC ID', 90, 'VNIC']) + printer = TablePrinter(title=_title, columns=_columns, column_separator='', text_truncate=False) - Parameters - ---------- - args: namespace - command line. - Returns - ------- - int: the IP version. - """ - if args.ipv4: - return 4 - if args.ipv6: - return 6 - return 4 + printer.printHeader() + for item in ret: + printer.printRow(item) + printer.printFooter() + printer.finish() -def get_vnic_utils(args): +def do_detach_vnic(detach_options): """ - Collect the VNIC data. + Detach and delete the VNIC with the given ocid or primary ip address Parameters ---------- - args: namespace - The command lind arguments. + detach_options : namespace + The argparse namespace. Returns ------- - VNICUtils: the data. - """ - _logger.debug('%s', where_am_i()) - vnic_utls = VNICUtils() + No return value on success;. - if 'exclude' in args and args.exclude: - for exc in args.exclude: - vnic_utls.exclude(exc) + Raises + ------ + Exception + if session cannot be acquired + if the VNIC cannot be detached - if 'include' in args and args.include: - for inc in args.include: - vnic_utls.include(inc) - return vnic_utls + """ + _logger.debug('%s', where_am_i()) + sess = get_oci_api_session() + if sess is None: + raise Exception("Failed to get API session.") + vnics = sess.this_instance().all_vnics() + for vnic in vnics: + v_ocid = vnic.get_ocid() + v_ip = vnic.get_private_ip() + if v_ocid == detach_options.ocid or v_ip == detach_options.ip_address: + if not vnic.is_primary(): + _logger.info('Detaching VNIC %s [%s]', v_ip, v_ocid) + macaddress = vnic.get_mac_address() + vnic.detach() + _logger.info('VNIC [%s] is detached.', v_ocid) + add_mac_to_nm(macaddress) + _logger.debug('Added mac address %s back to nm.', macaddress) + break + raise Exception("The primary VNIC cannot be detached.") + else: + _logger.error('VNIC %s [%s] is not attached to this instance.', detach_options.ip_address, detach_options.ocid) def get_subnet_ocid_from_arg(this_session, subnet_arg): @@ -1557,235 +1466,60 @@ def do_create_vnic(create_options): Exception if session cannot be acquired """ - _logger.debug('%s: %s', where_am_i(), create_options) - # needs the OCI SDK installed and configured - session = get_oci_api_session() - if session is None: - raise Exception("Failed to get API session.") - - the_instance = session.this_instance() - - subnet_id = None - if create_options.subnet: - # - # subnet data provided on command line. - subnet_id = get_subnet_ocid_from_arg(session, create_options.subnet) - else: - # - # no subnet data on the command line. - # - # if private ip provided, pick up subnet with matching IP - # else pick the subnet of the primary vnic - if create_options.ip_address: - # - # private ip provided, look for subnet the ip belongs to. - if is_valid_ip_address(create_options.ip_address): - subnet_id = get_subnet_ocid_from_ip(the_instance, create_options.ip_address) - else: - raise Exception('Invalid ip address format.') - else: - # - # No subnet nor ip provided, use the primary vnic. - _primary_v = [v for v in the_instance.all_vnics() if v.is_primary()][0] - subnet_id = _primary_v.get_subnet_id() - _logger.debug('Subnet ocid used: %s', subnet_id) - - try: - vnic = the_instance.attach_vnic(private_ip=create_options.ip_address, - assign_public_ip=create_options.assign_public_ip, - subnet_id=subnet_id, - nic_index=create_options.nic_index, - display_name=create_options.name, - ipv=create_options.ipv) - except Exception as e: - # raise Exception('Failed to create VNIC: %s' % str(e)) from e - raise ValueError('%s' % str(e)) from e - - if not isinstance(vnic, OCIVNIC): - raise ValueError('Failed to attach VNIC %s' % create_options.name) - - # - # - public_ip = vnic.get_public_ip() - if public_ip is not None: - _logger.info('Creating VNIC: %s (public IP %s)', vnic.get_private_ip(), public_ip) - else: - _logger.info('Creating VNIC: %s', vnic.get_private_ip()) - - -def ipv_not_supported(ipv): - """ - Write a messages attaching a vnic with primary ipv6 address is not (yet) supported. - Parameters - ---------- - ipv: int - The ipv version. - Returns - ------- - No return value. - """ - _logger.debug('%s', where_am_i()) - if ipv == 6: - _logger.warning('Attaching a vnic with a primary ipv%d address is not yet supported by OCI.', ipv) - sys.exit(1) - - -def attach_vnic(args): - """ - Attach a new Virtula Network Interface Card to the instance. - - Parameters - ---------- - args: namespace - The command line. - - Returns - ------- - bool: True - """ - _logger.debug('%s', where_am_i()) - args.ipv = get_ipv_version(args) - # - # OCI does not support creating a vnic with an ipv6 address only. - ipv_not_supported(args.ipv) - if 'nic_index' in args and args.nic_index != 0: - if not get_oci_api_session().this_shape().startswith("BM"): - _logger.error('--nic-index option ignored when not runnig on Bare Metal type of shape') - return 1 - try: - do_create_vnic(args) - except Exception as e: - _logger.debug('Cannot create the VNIC', exc_info=True) - _logger.error('%s', str(e)) - return 1 - # - # apply config of newly created vnic - time.sleep(25) - vnic_utils = VNICUtils() - vnic_utils.auto_config(None, deconfigured=False) - return True - - -def do_detach_vnic(detach_options): - """ - Detach and delete the VNIC with the given ocid or primary ip address - - Parameters - ---------- - detach_options : namespace - The argparse namespace. - - Returns - ------- - No return value on success;. - - Raises - ------ - Exception - if session cannot be acquired - if the VNIC cannot be detached - - """ - _logger.debug('%s', where_am_i()) - sess = get_oci_api_session() - if sess is None: - raise Exception("Failed to get API session.") - vnics = sess.this_instance().all_vnics() - for vnic in vnics: - v_ocid = vnic.get_ocid() - v_ip = vnic.get_private_ip() - if v_ocid == detach_options.ocid or v_ip == detach_options.ip_address: - if not vnic.is_primary(): - _logger.info('Detaching VNIC %s [%s]', v_ip, v_ocid) - macaddress = vnic.get_mac_address() - vnic.detach() - _logger.info('VNIC [%s] is detached.', v_ocid) - add_mac_to_nm(macaddress) - _logger.debug('Added mac address %s back to nm.', macaddress) - break - raise Exception("The primary VNIC cannot be detached.") - else: - _logger.error('VNIC %s [%s] is not attached to this instance.', detach_options.ip_address, detach_options.ocid) - - -def detach_vnic(args): - """ - Detach a new Virtula Network Interface Card to the instance. - - Parameters - ---------- - args: namespace - The command line. - - Returns - ------- - bool: True on success, false otherwise. - """ - _logger.debug('%s', where_am_i()) - try: - do_detach_vnic(args) - except Exception as e: - _logger.debug('Cannot detach VNIC', exc_info=True, stack_info=True) - # _logger.error('Cannot detach VNIC: %s', str(e)) - _logger.error('%s', str(e)) - return False - # if we are here session is alive: no check - vnic_utils = get_vnic_utils(args) - if get_oci_api_session().this_shape().startswith("BM"): - # in runnning on BM some cleanup is needed on the host - vnic_utils.auto_config(None, deconfigured=False) - return True - - -def do_add_secondary_addr(vnic_utils, add_options): - """ - Add a secondary private IP for an existing VNIC. - - Parameters - ---------- - vnic_utils : VNICUtils - The VNICUtils helper instance. - add_options : namespace - The argparse namespace. - - Returns - ------- - tuple - (private_IP,vnic_ocid) for the new IP on success; errors out with - return value 1 otherwise. - - Raises - ------ - Exception - On any error. - """ - _logger.debug('%s', where_am_i()) + _logger.debug('%s: %s', where_am_i(), create_options) # needs the OCI SDK installed and configured - sess = get_oci_api_session() - if sess is None: + session = get_oci_api_session() + if session is None: raise Exception("Failed to get API session.") - if add_options.ocid: - vnic = sess.get_vnic(vnic_id=add_options.ocid) - if vnic is None: - raise Exception("VNIC not found: %s" % add_options.ocid) - else: - vnics = sess.this_instance().all_vnics() - if len(vnics) > 1: - _logger.error("More than one VNIC found.Use the --ocid option to select the one to add a secondary IP for:") - for vnic in vnics: - _logger.error(" %s: %s", vnic.get_private_ip(), vnic.get_ocid()) - raise Exception("Too many VNICs found") - vnic = vnics[0] + the_instance = session.this_instance() - if add_options.ipv == 4: - priv_ip, ip_ocid = do_add_private_ipv4(vnic_utils, vnic, add_options.ip_address) - elif add_options.ipv == 6: - priv_ip, ip_ocid = do_add_private_ipv6(vnic_utils, vnic, add_options.ip_address) + subnet_id = None + if create_options.subnet: + # + # subnet data provided on command line. + subnet_id = get_subnet_ocid_from_arg(session, create_options.subnet) else: - raise Exception('Invalid ip version: %d' % add_options.ipv) + # + # no subnet data on the command line. + # + # if private ip provided, pick up subnet with matching IP + # else pick the subnet of the primary vnic + if create_options.ip_address: + # + # private ip provided, look for subnet the ip belongs to. + if is_valid_ip_address(create_options.ip_address): + subnet_id = get_subnet_ocid_from_ip(the_instance, create_options.ip_address) + else: + raise Exception('Invalid ip address format.') + else: + # + # No subnet nor ip provided, use the primary vnic. + _primary_v = [v for v in the_instance.all_vnics() if v.is_primary()][0] + subnet_id = _primary_v.get_subnet_id() + _logger.debug('Subnet ocid used: %s', subnet_id) - return priv_ip, ip_ocid + try: + vnic = the_instance.attach_vnic(private_ip=create_options.ip_address, + assign_public_ip=create_options.assign_public_ip, + subnet_id=subnet_id, + nic_index=create_options.nic_index, + display_name=create_options.name, + ipv=create_options.ipv) + except Exception as e: + # raise Exception('Failed to create VNIC: %s' % str(e)) from e + raise ValueError('%s' % str(e)) from e + + if not isinstance(vnic, OCIVNIC): + raise ValueError('Failed to attach VNIC %s' % create_options.name) + + # + # + public_ip = vnic.get_public_ip() + if public_ip is not None: + _logger.info('Creating VNIC: %s (public IP %s)', vnic.get_private_ip(), public_ip) + else: + _logger.info('Creating VNIC: %s', vnic.get_private_ip()) def do_add_private_ipv4(vnic_utils, vnic, ip_address): @@ -1846,36 +1580,55 @@ def do_add_private_ipv6(vnic_utils, vnic, ip_address): return priv_ipv6.get_address(), vnic.get_ocid() -def add_secondary_address(args): +def do_add_secondary_addr(vnic_utils, add_options): """ - Add a secondary address to a vnic. + Add a secondary private IP for an existing VNIC. Parameters ---------- - args: namespace - The command line. + vnic_utils : VNICUtils + The VNICUtils helper instance. + add_options : namespace + The argparse namespace. Returns ------- - bool: True on success, False otherwise. + tuple + (private_IP,vnic_ocid) for the new IP on success; errors out with + return value 1 otherwise. + + Raises + ------ + Exception + On any error. """ _logger.debug('%s', where_am_i()) - args.ipv = get_ipv_version(args) - if args.ip_address: - if is_valid_ip_address(args.ip_address): - args.ipv = ipv_version(args.ip_address) - else: - _logger.error('Invalid IP address provided: %s', args.ip_address) - return False - vnic_utils = get_vnic_utils(args) - try: - ip, vnic_id = do_add_secondary_addr(vnic_utils, args) - _logger.info("IP %s has been assigned to vnic %s.", ip, vnic_id) - except Exception as e: - _logger.debug('%s', str(e), stack_info=True) - _logger.error('%s', str(e)) - return False - return True + # needs the OCI SDK installed and configured + sess = get_oci_api_session() + if sess is None: + raise Exception("Failed to get API session.") + + if add_options.ocid: + vnic = sess.get_vnic(vnic_id=add_options.ocid) + if vnic is None: + raise Exception("VNIC not found: %s" % add_options.ocid) + else: + vnics = sess.this_instance().all_vnics() + if len(vnics) > 1: + _logger.error("More than one VNIC found.Use the --ocid option to select the one to add a secondary IP for:") + for vnic in vnics: + _logger.error(" %s: %s", vnic.get_private_ip(), vnic.get_ocid()) + raise Exception("Too many VNICs found") + vnic = vnics[0] + + if add_options.ipv == 4: + priv_ip, ip_ocid = do_add_private_ipv4(vnic_utils, vnic, add_options.ip_address) + elif add_options.ipv == 6: + priv_ip, ip_ocid = do_add_private_ipv6(vnic_utils, vnic, add_options.ip_address) + else: + raise Exception('Invalid ip version: %d' % add_options.ipv) + + return priv_ip, ip_ocid def do_remove_secondary_addr(vnic_utils, delete_options): @@ -1902,7 +1655,7 @@ def do_remove_secondary_addr(vnic_utils, delete_options): ip_addr = delete_options.ip_address # # ipv4 or ipv6; valid ip address is verified by the ip_address_validator. - # ip_version = ipv_version(ip_addr) + ip_version = ipv_version(ip_addr) # # needs the OCI SDK installed and configured sess = get_oci_api_session() @@ -1931,99 +1684,100 @@ def do_remove_secondary_addr(vnic_utils, delete_options): return vnic_utils.del_private_ip(ip_addr, vnic_id) -def remove_secondary_address(args): +def get_vnic_utils(args): """ - Remove a secondary address from a vnic. + Collect the VNIC data. Parameters ---------- args: namespace - The command line. + The command lind arguments. Returns ------- - bool: True on success, False otherwise. + VNICUtils: the data. """ _logger.debug('%s', where_am_i()) - vnic_utils = get_vnic_utils(args) - try: - (ret, out) = do_remove_secondary_addr(vnic_utils, args) - if ret != 0: - raise Exception('Cannot delete ip: %s' % out) - except Exception as e: - _logger.debug('Failed to delete private IP: %s', str(e), stack_info=True) - # _logger.error('Failed to delete private IP: %s', str(e)) - _logger.error('%s', str(e)) - return False - return True + vnic_utls = VNICUtils() + + if 'exclude' in args and args.exclude: + for exc in args.exclude: + vnic_utls.exclude(exc) + + if 'include' in args and args.include: + for inc in args.include: + vnic_utls.include(inc) + return vnic_utls -def configure(args): +def show_network(vnic_utls, args): """ + Display the network information. + Parameters ---------- + vnic_utls: VNICUtils + The vnic data. args: namespace - The command line. - - Returns - ------- - Configure vnics. + The command line arguments. Returns ------- - bool: True on success, False otherwise. + int: 0 on success, 1 otherwise. """ _logger.debug('%s', where_am_i()) - vnic_utils = get_vnic_utils(args) - - if 'namespace' in args and args.namespace: - try: - vnic_utils.set_namespace(args.namespace) - except Exception as e: - _logger.debug('Failed to set namespace: %s', str(e), stack_info=True) - _logger.error('Failed to set namespace: %s', str(e)) - return False - - if 'start_sshd' in args and args.start_sshd: + # + # for compatibility mode, oci-network-config show should provide the same output as oci-network-config --show; + # if output-mode is specified, compatiblity requirement is dropped. + showerror = False + if args.compat_output: + compat_show_vnics_information() + else: try: - vnic_utils.set_sshd(args.start_sshd) + do_show_information(vnic_utls, args.output_mode, args.details) except Exception as e: - _logger.debug('Failed to start sshd: %s', str(e), stack_info=True) - _logger.error('Failed to start sshd: %s', str(e)) - return False - - try: - vnic_utils.auto_config(args.sec_ip) - _logger.info('Configured ') - except Exception as e: - _logger.debug('Failed to configure network: %s', str(e), stack_info=True) - _logger.error('Failed to configure network: %s', str(e)) - return False - return True + _logger.debug('Cannot show information', exc_info=True) + _logger.error('Cannot show information: %s', str(e)) + showerror = True + if args.output_mode == 'table': + show_os_network_config(vnic_utls) + return 1 if showerror else 0 -def unconfigure(args): +def get_ipv_version(args): """ - Unconfigure vnics.. + Get the ip version from the commandline, default is 4. Parameters ---------- args: namespace - The command line. + command line. + Returns + ------- + int: the IP version. + """ + if args.ipv4: + return 4 + if args.ipv6: + return 6 + return 4 + +def ipv_not_supported(ipv): + """ + Write a messages attaching a vnic with primary ipv6 address is not (yet) supported. + Parameters + ---------- + ipv: int + The ipv version. Returns ------- - bool: True on success, False otherwise. + No return value. """ _logger.debug('%s', where_am_i()) - vnic_utils = get_vnic_utils(args) - try: - vnic_utils.auto_deconfig(args.sec_ip) - _logger.info('Unconfigured ') - except Exception as e: - _logger.debug('Failed to unconfigure network: %s', str(e), stack_info=True) - _logger.error('Failed to unconfigure network: %s', str(e)) - return True + if ipv == 6: + _logger.warning('Attaching a vnic with a primary ipv%d address is not yet supported by OCI.', ipv) + sys.exit(1) def main(): @@ -2036,43 +1790,138 @@ def main(): 0 on success; 1 on failure. """ - sub_commands = {'usage': show_usage, - 'show': show_network, - 'show-vnics': show_vnics, - 'show-vnics-all': show_vnics_all, - 'show-vcns': show_vcns, - 'show-subnets': show_subnets, - 'attach-vnic': attach_vnic, - 'detach-vnic': detach_vnic, - 'add-secondary-addr': add_secondary_address, - 'remove-secondary-addr': remove_secondary_address, - 'configure': configure, - 'unconfigure': unconfigure - } - parser = get_arg_parser() args = parser.parse_args() if args.quiet: _logger.setLevel(logging.WARNING) - if args.command is None or args.command == 'usage': + if not args.command: + parser.print_help() + return 1 + + if args.command == 'usage': parser.print_help() return 0 - # - # operator needs to have root priviliges. + if not is_root_user(): _logger.error("This program needs to be run with root privileges.") return 1 - try: - res = sub_commands[args.command](args) - if not res: - raise NetworkConfigException('Failed to complete %s.' % sub_commands[args.command].__name__) - return 0 - except Exception as e: - _logger.error('*** ERROR *** %s', str(e)) - return 1 + vnic_utils = get_vnic_utils(args) + + if args.command == 'show': + return show_network(vnic_utils, args) + + if args.command == 'show-vnics': + return show_vnics(args) + + if args.command == 'show-vnics-all': + args.no_truncate = True + args.details = True + args.ocid = None + args.ip_address = None + args.name = None + return show_vnics(args) + + if args.command == 'show-vcns': + return show_vcn(args) + + if args.command == 'show-subnets': + return show_subnet(args) + + if args.command == 'attach-vnic': + args.ipv = get_ipv_version(args) + # + # OCI does not support creating a vnic with an ipv6 address only. + ipv_not_supported(args.ipv) + if 'nic_index' in args and args.nic_index != 0: + if not get_oci_api_session().this_shape().startswith("BM"): + _logger.error('--nic-index option ignored when not runnig on Bare Metal type of shape') + return 1 + try: + do_create_vnic(args) + except Exception as e: + _logger.debug('Cannot create the VNIC', exc_info=True) + _logger.error('%s', str(e)) + return 1 + # apply config of newly created vnic + time.sleep(25) + vnic_utils = VNICUtils() + vnic_utils.auto_config(None, deconfigured=False) + + if args.command == 'detach-vnic': + try: + do_detach_vnic(args) + except Exception as e: + _logger.debug('Cannot detach VNIC', exc_info=True, stack_info=True) + # _logger.error('Cannot detach VNIC: %s', str(e)) + _logger.error('%s', str(e)) + return 1 + # if we are here session is alive: no check + if get_oci_api_session().this_shape().startswith("BM"): + # in runnning on BM some cleanup is needed on the host + vnic_utils.auto_config(None, deconfigured=False) + + if args.command == "add-secondary-addr": + args.ipv = get_ipv_version(args) + if args.ip_address: + if is_valid_ip_address(args.ip_address): + args.ipv = ipv_version(args.ip_address) + else: + _logger.error('Invalid IP address provided: %s', args.ip_address) + return 1 + try: + ip, vnic_id = do_add_secondary_addr(vnic_utils, args) + _logger.info("IP %s has been assigned to vnic %s.", ip, vnic_id) + except Exception as e: + _logger.debug('%s', str(e), stack_info=True) + # _logger.error('Failed to add private IP: %s', str(e)) + _logger.error('%s', str(e)) + return 1 + + if args.command == "remove-secondary-addr": + try: + (ret, out) = do_remove_secondary_addr(vnic_utils, args) + if ret != 0: + raise Exception('Cannot delete ip: %s' % out) + except Exception as e: + _logger.debug('Failed to delete private IP: %s', str(e), stack_info=True) + # _logger.error('Failed to delete private IP: %s', str(e)) + _logger.error('%s', str(e)) + return 1 + + if 'namespace' in args and args.namespace: + try: + vnic_utils.set_namespace(args.namespace) + except Exception as e: + _logger.debug('Failed to set namespace: %s', str(e), stack_info=True) + _logger.error('Failed to set namespace: %s', str(e)) + + if 'start_sshd' in args and args.start_sshd: + try: + vnic_utils.set_sshd(args.start_sshd) + except Exception as e: + _logger.debug('Failed to start sshd: %s', str(e), stack_info=True) + _logger.error('Failed to start sshd: %s', str(e)) + + if args.command == 'configure': + try: + vnic_utils.auto_config(args.sec_ip) + _logger.info('Configured ') + except Exception as e: + _logger.debug('Failed to configure network: %s', str(e), stack_info=True) + _logger.error('Failed to configure network: %s', str(e)) + + if args.command == 'unconfigure': + try: + vnic_utils.auto_deconfig(args.sec_ip) + _logger.info('Unconfigured ') + except Exception as e: + _logger.debug('Failed to unconfigure network: %s', str(e), stack_info=True) + _logger.error('Failed to unconfigure network: %s', str(e)) + + return 0 if __name__ == "__main__": diff --git a/lib/oci_utils/impl/oci_notify_main.py b/lib/oci_utils/impl/oci_notify_main.py index 83dc8bb4..1f40c9cb 100644 --- a/lib/oci_utils/impl/oci_notify_main.py +++ b/lib/oci_utils/impl/oci_notify_main.py @@ -29,8 +29,6 @@ from datetime import datetime import oci as oci_sdk -from oci_utils import is_root_user -from oci_utils import where_am_i from oci_utils import _configuration as OCIUtilsConfiguration from oci_utils.impl.auth_helper import OCIAuthProxy from oci_utils.metadata import InstanceMetadata @@ -60,63 +58,39 @@ OCI_CLI_CONFIG_FILE = NOTIFY_CONFIG_DIR + '/oci_cli.conf' -def def_usage_parser(s_parser): +def parse_args(): """ - Define the usage parser. + Parse the command line arguments and return an object representing the + command line (as returned by argparse's parse_args()). - Parameters - ---------- - s_parser: subparsers. + Arguments: + config + message + -t|--title + -f|--file Returns ------- - ArgumentParser: the usage subcommand parser. - """ - usage_parser = s_parser.add_parser('usage', - description='Displays usage', - help='Displays usage' - ) - return usage_parser - - -def def_config_parser(s_parser): + The command line namespace. """ - Define the config parser. - - Parameters - ---------- - s_parser:subparsers + _logger.debug('_parse_args') + extra_descr = '' + for helpline in __doc__.splitlines(): + extra_descr += '%s\n' % (helpline.replace('MAX_MESSAGE_TITLE_LEN', str(MAX_MESSAGE_TITLE_LEN)) + .replace('CHUNK_SIZE', str(CHUNK_SIZE)) + .replace('MAX_MESSAGE_CHUNKS', str(MAX_MESSAGE_CHUNKS))) + parser = argparse.ArgumentParser(prog='oci-notify', + description='%s' % extra_descr) + sub_parser = parser.add_subparsers(dest='mode') - Returns - ------- - ArgumentParser: the config parser - """ - config_parser = s_parser.add_parser('config', - description='Configure the notificatio server.', - help='Configure the notification server.') + config_parser = sub_parser.add_parser('config', help='Configure the notification server.') config_parser.add_argument(action='store', dest='notification_ocid', type=str, help='The ocid of the notification topic.') - return config_parser - -def def_message_parser(s_parser): - """ - Define the send message parser. - - Parameters - ---------- - s_parser: subparsers. - - Returns - ------- - ArgumentParser: the send message parser. - """ - message_parser = s_parser.add_parser('message', - description='Send a message.', - help='Send a message.') + message_parser = sub_parser.add_parser('message', help='Send a message.') message_parser.add_argument('-t', '--title', action='store', dest='message_title', @@ -129,61 +103,18 @@ def def_message_parser(s_parser): required=True, type=str, help='The message data.') - return message_parser - - -def get_args_parser(): - """ - Parse the command line arguments and return an object representing the - command line (as returned by argparse's parse_args()). - - Arguments: - config - message - -t|--title - -f|--file - - Returns - ------- - The command line namespace. - """ - _logger.debug('_get_args_parser') - extra_descr = '' - for helpline in __doc__.splitlines(): - extra_descr += '%s\n' % (helpline.replace('MAX_MESSAGE_TITLE_LEN', str(MAX_MESSAGE_TITLE_LEN)) - .replace('CHUNK_SIZE', str(CHUNK_SIZE)) - .replace('MAX_MESSAGE_CHUNKS', str(MAX_MESSAGE_CHUNKS))) - parser = argparse.ArgumentParser(prog='oci-notify', - description='%s' % extra_descr) - subparser = parser.add_subparsers(dest='mode') - # - # usage - _ = def_usage_parser(subparser) - # - # config - _ = def_config_parser(subparser) - # - # send message - _ = def_message_parser(subparser) - return parser -def show_usage(usage_args): +def is_root(): """ - Wrapper for showing usage info. - - Parameters - ---------- - usage_args: - The command line arguments. + Verify is operator is the root user. Returns ------- bool: True on success, False otherwise. """ - _logger.debug('%s', where_am_i()) - return True + return bool(os.getuid() == 0) def config_notification_service_wrap(config_args): @@ -199,7 +130,7 @@ def config_notification_service_wrap(config_args): ------- bool: True on success, False otherwise. """ - _logger.debug('%s: %s', where_am_i(), config_args.notification_ocid) + _logger.debug('_config_notification_service_wrap: %s', config_args.notification_ocid) cfg = NotificationConfig(config_args.notification_ocid, OCI_CONFIG_FILE) cfg_title, cfg_message = cfg.config_notification_service(config_args.notification_ocid) cfg_res = handle_message(cfg_title, cfg_message) @@ -220,7 +151,7 @@ def handle_message_wrap(message_args): ------- bool: True on success, False otherwise. """ - _logger.debug('%s: %s', where_am_i(), message_args) + _logger.debug('_handle_message_wrap: %s', message_args) message_title = message_args.message_title message_file = message_args.message_file try: @@ -246,7 +177,7 @@ def handle_message(title, message): ------- bool: True on success, False otherwise. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_handle_message') _logger.debug('title %s', title) _logger.debug('message %s', message) try: @@ -264,7 +195,7 @@ class NotificationException(Exception): """ def __init__(self, message=None): """ - Initialisation of the Oci Notification Exception. + Initialisation of the Oci Migrate Exception. Parameters ---------- @@ -327,7 +258,7 @@ def _read_oci_config(fname, profile='DEFAULT'): Exception If the configuration file does not exist or is not readable. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_read_oci_config') full_fname = os.path.expanduser(fname) try: oci_config = oci_sdk.config.from_file(full_fname, profile) @@ -354,7 +285,7 @@ def get_auth_method(self, authentication_method=None): the authentication method which passed or NONE. [NONE | DIRECT | PROXY | AUTO | IP] """ - _logger.debug('%s', where_am_i()) + _logger.debug('_get_auth_method') if authentication_method is None: auth_method = OCIUtilsConfiguration.get('auth', 'auth_method') else: @@ -406,7 +337,7 @@ def _proxy_authenticate(self): Exception The authentication using direct mode is noit possible """ - _logger.debug('%s', where_am_i()) + _logger.debug('_proxy_authenticate') if os.geteuid() != 0: raise Exception('Must be root to use Proxy authentication') @@ -434,7 +365,7 @@ def _direct_authenticate(self): Exception The authentication using direct mode is not possible """ - _logger.debug('%s', where_am_i()) + _logger.debug('_direct_authenticate') try: self._oci_config = self._read_oci_config(fname=self._oci_config_file, profile=self._oci_config_profile) self._identity_client = oci_sdk.identity.IdentityClient(self._oci_config) @@ -457,7 +388,7 @@ def _ip_authenticate(self): Exception If IP authentication fails. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_ip_authenticate') try: self._signer = oci_sdk.auth.signers.InstancePrincipalsSecurityTokenSigner() self._identity_client = oci_sdk.identity.IdentityClient(config={}, signer=self._signer) @@ -518,7 +449,7 @@ def _get_ons_control_client(): ------- class: oci.ons.notification_control_plane_client.NotificationControlPlaneClient """ - _logger.debug('%s', where_am_i()) + _logger.debug('_get_ons_control_client') identity_client = OnsIdentity() return identity_client.ons_control_client() @@ -530,7 +461,7 @@ def _get_topic_list(self): ------- list: List of available topics. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_get_topic_list') try: ons_topics = self._get_ons_control_client().list_topics(compartment_id=self._compartment_id).data topics_list = [topic.topic_id for topic in ons_topics] @@ -554,7 +485,7 @@ def _topic_exist(self, notification_topic): ------- bool: True if topic in list, False if topic not in list, (True if list is not available for any reason) """ - _logger.debug('%s', where_am_i()) + _logger.debug('_topic_exist') topics = self._get_topic_list() return bool(notification_topic in topics) if 'FAILED TO RETRIEVE TOPIC LIST' not in topics else 'FAILED' @@ -566,7 +497,7 @@ def get_notification_topic(self): ------- str: the notification topic. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_Collect the notification topic.') if not os.path.exists(self._config_file): raise NotificationException('Configuration for oci-notify not found.') @@ -603,7 +534,7 @@ def convert_oci_config(self): ------- bool: True on success, False otherwise. """ - _logger.debug('%s: %s', where_am_i(), self._config_file) + _logger.debug('_convert_oci_config_file: %s', self._config_file) # # backup file configfile_bck = self._config_file + '_backup_' + datetime.today().strftime('%Y-%m-%d-%H%M%S') @@ -638,7 +569,7 @@ def config_notification_service(self, notification_ocid): ------- tuple: config title, config message """ - _logger.debug('%s: %s', where_am_i(), notification_ocid) + _logger.debug('_config_notification_service: %s', notification_ocid) try: ocid_check = re.compile(r'^ocid\d\.onstopic\.') except Exception as e: @@ -749,7 +680,7 @@ def _get_ons_data_client(): ------- class: oci.ons.notification_data_plane_client.NotificationDataPlaneClient """ - _logger.debug('%s', where_am_i()) + _logger.debug('_get_ons_data_client') identity_client = OnsIdentity() return identity_client.ons_data_client() @@ -760,7 +691,7 @@ def _get_topic(self): ------- bool: True on success, raises an exception otherwise. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_get_topic') try: config_data = NotificationConfig() self._topic = config_data.get_notification_topic() @@ -777,7 +708,7 @@ def _message_title(self): ------- str: the message subject. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_message_title') subject = self._message[:MAX_MESSAGE_TITLE_LEN] _logger.debug('_Message subject: %s', subject) return subject @@ -806,7 +737,7 @@ def file_message(message): ------- tuple: (bool: accessible, int: size, str: path to local file) """ - _logger.debug('%s: %s', where_am_i(), message) + _logger.debug('_file %s', message) msg_access = False msg_size = -1 if os.path.isfile(self._message) and os.access(message, os.R_OK): @@ -831,7 +762,7 @@ def url_message(message): ------- tuple: (bool: accessible, int: size, str: path to local file) """ - _logger.debug('%s: %s', where_am_i(), message) + _logger.debug('_url %s', message) msg_access = False msg_size = -1 msg_fn = None @@ -875,7 +806,7 @@ def send_notification(self): ------- bool: True on success, raises an exception otherwise. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_send_notification') try: self._get_topic() except Exception as e: @@ -927,7 +858,7 @@ def send_message_chunk(self, chunk, nb, nbtot): ------- bool: True on success, raises an exception otherwise. """ - _logger.debug('%s', where_am_i()) + _logger.debug('_send_message_chunk') try: _logger.debug('_Send chunk %d of %d', nb, nbtot) if nbtot <= 1: @@ -967,20 +898,19 @@ def main(): # locale os.environ['LC_ALL'] = "%s" % lc_all - if not is_root_user(): + if not is_root(): _logger.error('This program needs to be run with root privileges.') sys.exit(1) - parser = get_args_parser() + sub_commands = {'config': config_notification_service_wrap, + 'message': handle_message_wrap} + + parser = parse_args() args = parser.parse_args() - if args.mode is None or args.mode == 'usage': + if args.mode is None: parser.print_help() sys.exit(0) - sub_commands = {'usage': show_usage, - 'config': config_notification_service_wrap, - 'message': handle_message_wrap} - try: res = sub_commands[args.mode](args) if not res: diff --git a/lib/oci_utils/impl/oci_resources.py b/lib/oci_utils/impl/oci_resources.py index 18076fee..5be448eb 100644 --- a/lib/oci_utils/impl/oci_resources.py +++ b/lib/oci_utils/impl/oci_resources.py @@ -1184,7 +1184,7 @@ def add_private_ipv6(self, private_ipv6=None, display_name=None): def find_private_ipv4(self, ipv4_address): """ - Find a secondary private IPv4 based on its IP address. + Find a secondary private IPv6 based on its IP address. Parameters ---------- @@ -1917,6 +1917,11 @@ def get_vcn_name(self): """ OCISubnet._logger.debug('%s', where_am_i()) return self._oci_session.get_vcn(vcn_id=self._data.vcn_id).get_display_name() + # this_vcn_ocid = self.get_vcn_id() + # for vcn in self._oci_session.all_vcns(): + # if vcn.get_ocid() == this_vcn_ocid: + # return vcn.get_display_name() + # return '' def get_security_list_ids(self): """ @@ -2320,7 +2325,7 @@ def is_attached(self): OCIVolume._logger.debug('%s', where_am_i()) return self.volume_lifecycle == OCI_ATTACHMENT_STATE.ATTACHED - def get_size(self, format_str=OCI_VOLUME_SIZE_FMT.HUMAN.name): + def get_size(self, format_str=None): """ Get the size of the volume. diff --git a/lib/oci_utils/impl/oci_test_ip_auth_main.py b/lib/oci_utils/impl/oci_test_ip_auth_main.py index f6457481..c6c92ffe 100644 --- a/lib/oci_utils/impl/oci_test_ip_auth_main.py +++ b/lib/oci_utils/impl/oci_test_ip_auth_main.py @@ -81,7 +81,7 @@ def test_collecting_instance_data(instance_ocid): 'with Instance Principal Authentication using OCI SDK only. Verify the configuration or switch to ' 'Direct Authentication.\n') print('Exception: %s' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -106,7 +106,7 @@ def test_collecting_compartments_data(): 'with Instance Principal Authentication using OCI SDK only. Verify the configuration or switch ' 'to Direct Authentication.\n') print('Exception: %s' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -135,7 +135,7 @@ def test_collecting_instances_data(compartment_ocid): 'with Instance Principal Authentication using OCI SDK only. Verify the configuration or switch to ' 'Direct Authentication.\n') print('Exception: %s' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -164,7 +164,7 @@ def test_collecting_all_volumes_data(compartment_id): 'with Instance Principal Authentication using OCI SDK only. Verify the configuration or switch to ' 'Direct Authentication.\n') print('Exception: %s' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -199,7 +199,7 @@ def test_collecting_attached_volume_data(compartment_ocid, instance_ocid, instan 'with Instance Principal Authentication using OCI SDK only. Verify the configuration or switch to ' 'Direct Authentication.\n') print('Exception: %s' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -228,7 +228,7 @@ def test_collecting_notification_topics(compartment_ocid, instance_name): print('\n--- ERROR --- Unable to authenticate correctly for collecting notification service topics ' 'with Instance Principal Authentication using OCI SDK only: %s\nVerify the configuration or switch to ' 'Direct Authentication.\n' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -257,7 +257,7 @@ def test_collecting_vcns_data(compartment_id): print('\n--- ERROR --- Unable to authenticate correctly for collecting the vcns ' 'with Instance Principal Authentication using OCI SDK only: %s\nVerify the configuration or switch to ' 'Direct Authentication.\n' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -286,7 +286,7 @@ def test_collecting_subnets_data(compartment_id): print('\n--- ERROR --- Unable to authenticate correctly for collecting the subnet list ' 'with Instance Principal Authentication using OCI SDK only: %s\nVerify the configuration or switch to ' 'Direct Authentication.\n' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False @@ -315,7 +315,7 @@ def test_collecting_vnics_data(compartment_id): print('\n--- ERROR --- Unable to authenticate correctly for collecting the vnic list ' 'with Instance Principal Authentication using OCI SDK only: %s\nVerify the configuration or switch to ' 'Direct Authentication.\n' % str(e)) - # traceback.print_exception(*sys.exc_info()) + traceback.print_exception(*sys.exc_info()) return False diff --git a/lib/oci_utils/impl/ocid_main.py b/lib/oci_utils/impl/ocid_main.py index 2323277b..8e80db56 100644 --- a/lib/oci_utils/impl/ocid_main.py +++ b/lib/oci_utils/impl/ocid_main.py @@ -214,7 +214,7 @@ def public_ip_func(context, func_logger): Returns ------- dict - Dictionary containing the external IP address. + Dictionary containiong the external IP address. """ if 'oci_sess' not in context: oci_sess = None @@ -256,6 +256,7 @@ def iscsi_func(context, func_logger): The new context. """ if 'oci_sess' not in context: + # func_logger.debug('__GT__ oci sess NOT in context') oci_sess = None try: oci_sess = oci_utils.oci_api.OCISession() @@ -290,6 +291,8 @@ def iscsi_func(context, func_logger): 'offline_vols': {}, 'auto_detach': auto_detach, 'detach_retry': detach_retry, } + # else: + # func_logger.debug('__GT__ oci sess in context') # devices currently attached session_devs = oci_utils.iscsiadm.session() @@ -315,68 +318,64 @@ def iscsi_func(context, func_logger): # ------------------------------------------------------------------------------------- # possible change for LINUX-11440; comment out the in-between - # first verify if user has authorisation to list volumes; if so, use this to get a list of volumes; - # if not, switch to scanning the ipaddresses:3260 scan for new volumes. - volumes = None - if context['oci_sess'] is not None: - try: - # - # get a list of volumes attached to the instance. - instance = context['oci_sess'].this_instance() - if instance is None: - func_logger.debug('Cannot get current instance.') - else: - volumes = instance.all_volumes() - except Exception as e: - func_logger.debug('User is not authorized to list all volumes, switch to scanning.') - else: - func_logger.debug('No oci session in the context, switch to scanning.') + # verify if user has authorisation to list volumes; if not, scan for new volumes. + # volumes = None + # if context['oci_sess'] is not None: + # try: + # # + # # get a list of volumes attached to the instance. + # instance = context['oci_sess'].this_instance() + # if instance is None: + # func_logger.debug('Cannot get current instance.') + # else: + # volumes = instance.all_volumes() + # except Exception as e: + # func_logger.debug('User is not authorized to list all volumes.') # ------------------------------------------------------------------------------------- # # volumes connected to this instance inst_volumes = [] - # if context['oci_sess'] is not None: - # # func_logger.debug('__GT__ context[oci sess] is NOT none') - # # - # # get a list of volumes attached to the instance - # instance = context['oci_sess'].this_instance() - # if instance is None: - # func_logger.debug('Cannot get current instance.') - # else: - # volumes = instance.all_volumes() - # for v in volumes: - # vol = {'iqn': v.get_iqn(), - # 'ipaddr': v.get_portal_ip(), - # 'user': v.get_user(), - # 'password': v.get_password()} - # inst_volumes.append(vol) - # if v.get_portal_ip() in all_iqns: - # all_iqns[v.get_portal_ip()].append(v.get_iqn()) - # else: - # all_iqns[v.get_portal_ip()] = [v.get_iqn()] - # func_logger.debug('All volumes: %s', all_iqns) + if context['oci_sess'] is not None: + # func_logger.debug('__GT__ context[oci sess] is NOT none') + # + # get a list of volumes attached to the instance + instance = context['oci_sess'].this_instance() + if instance is None: + func_logger.debug('Cannot get current instance.') + else: + volumes = instance.all_volumes() + for v in volumes: + vol = {'iqn': v.get_iqn(), + 'ipaddr': v.get_portal_ip(), + 'user': v.get_user(), + 'password': v.get_password()} + inst_volumes.append(vol) + if v.get_portal_ip() in all_iqns: + all_iqns[v.get_portal_ip()].append(v.get_iqn()) + else: + all_iqns[v.get_portal_ip()] = [v.get_iqn()] + func_logger.debug('All volumes: %s', all_iqns) # ------------------------------------------------------------------------------------- # # possible change for LINUX-11440; comment out the above - if bool(volumes): - # - # we have a list of volumes collected from the oci-session, only formatting it. - for v in volumes: - vol = {'iqn': v.get_iqn(), - 'ipaddr': v.get_portal_ip(), - 'user': v.get_user(), - 'password': v.get_password()} - inst_volumes.append(vol) - if v.get_portal_ip() in all_iqns: - all_iqns[v.get_portal_ip()].append(v.get_iqn()) - else: - all_iqns[v.get_portal_ip()] = [v.get_iqn()] - func_logger.debug('All volumes: %s', all_iqns) + # if bool(volumes): + # for v in volumes: + # vol = {'iqn': v.get_iqn(), + # 'ipaddr': v.get_portal_ip(), + # 'user': v.get_user(), + # 'password': v.get_password()} + # inst_volumes.append(vol) + # if v.get_portal_ip() in all_iqns: + # all_iqns[v.get_portal_ip()].append(v.get_iqn()) + # else: + # all_iqns[v.get_portal_ip()] = [v.get_iqn()] + # func_logger.debug('All volumes: %s', all_iqns) # # ------------------------------------------------------------------------------------- else: + # func_logger.debug('__GT__ context[oci sess] is none') # - # we do not have a list of volumes yet, fall back to ip address scanning to collect the available information. + # fall back to scanning func_logger.debug('Scan for volumes.') for r in range(context['max_volumes'] + 1): ipaddr = "169.254.2.%d" % (r + 1) @@ -541,6 +540,8 @@ def iscsi_func(context, func_logger): # connected to the instance inst_iqns = [vol['iqn'] for vol in inst_volumes] for iqn in ignore_iqns: + # if iqn not in inst_iqns: + # GT if iqn in inst_iqns: func_logger.debug("Removing iqn %s from ignore list" % iqn) ignore_iqns.remove(iqn) @@ -645,6 +646,7 @@ def start_thread(name, repeat): true_list = ['true', 'True', 'TRUE'] + # __ocid_logger.debug('__GT__ ocid %s', list(OCIUtilsConfiguration.items('public_ip'))) if name == 'public_ip': is_enabled = OCIUtilsConfiguration.get('public_ip', 'enabled') if is_enabled not in true_list: diff --git a/lib/oci_utils/impl/row_printer_helpers.py b/lib/oci_utils/impl/row_printer_helpers.py index 75ed4e10..590e8652 100644 --- a/lib/oci_utils/impl/row_printer_helpers.py +++ b/lib/oci_utils/impl/row_printer_helpers.py @@ -136,7 +136,6 @@ def get_value_data(struct, data): func = data['func'] if 'func' in data else None item = data['item'] if 'item' in data else None lfunc = data['lfunc'] if 'lfunc' in data else None - attrib = data['attrib'] if 'attrib' in data else None val = None value = '-' if func is not None: @@ -187,15 +186,6 @@ def get_value_data(struct, data): _logger.debug('Failed to collect %s: %s', lfunc, str(e)) return '-', 1 - elif attrib is not None: - # get an attriburte - try: - val = getattr(struct, attrib) - except Exception as e: - _logger.debug('Failed to collect %s: %s', attrib, str(e)) - return '-', 1 - - if bool(val): if data['type'] == 'str': value = data['convert'](val) if 'convert' in data else val diff --git a/lib/oci_utils/impl/virt/sysconfig.py b/lib/oci_utils/impl/virt/sysconfig.py index 140ee60b..6f839766 100644 --- a/lib/oci_utils/impl/virt/sysconfig.py +++ b/lib/oci_utils/impl/virt/sysconfig.py @@ -10,6 +10,7 @@ import logging import stat from .. import sudo_utils +from .. import IF_NAME_PREFIX from ..network_helpers import network_prefix_to_mask _logger = logging.getLogger('oci-utils.sysconfig') @@ -396,14 +397,12 @@ def make_vf_name(name): return name -def make_vlan_name(parent, vlan_id): +def make_vlan_name(vlan_id): """ Create a VLAN name. Parameters ---------- - parent : str - The parent interface. vlan_id : The vlan id. @@ -412,7 +411,7 @@ def make_vlan_name(parent, vlan_id): str The VLAN name. """ - return '{}.{}'.format(parent, vlan_id) + return '{}{}'.format(IF_NAME_PREFIX, vlan_id) def make_vf(name, mac, ip=None, prefix=None): @@ -491,7 +490,7 @@ def make_vlan_with_ip(parent, vlan, mac, ip, prefix): ------- The VLAN interface file contents. """ - name = make_vlan_name(parent, vlan) + name = make_vlan_name(vlan) if ip and prefix: return ('vm-{}'.format(name), {'DEVICE': name, diff --git a/lib/oci_utils/impl/virt/virt_check.py b/lib/oci_utils/impl/virt/virt_check.py index ee9f34c2..da5bc48d 100644 --- a/lib/oci_utils/impl/virt/virt_check.py +++ b/lib/oci_utils/impl/virt/virt_check.py @@ -35,9 +35,9 @@ def iommu_check(): bool True on success, False otherwise. """ - iommu_enabled_exp = "IOMMU.*enabled" + iommu_on_exp = "iommu=on" output = sudo_utils.call_popen_output( - ['/bin/dmesg', '|', 'egrep', '"{}"'.format(iommu_enabled_exp)]) + ['cat /proc/cmdline', '|', 'egrep', '"{}"'.format(iommu_on_exp)]) if not output: _logger.debug('IOMMU flag not set on kernel') return False diff --git a/lib/oci_utils/iscsiadm.py b/lib/oci_utils/iscsiadm.py index a2c09db4..80266225 100644 --- a/lib/oci_utils/iscsiadm.py +++ b/lib/oci_utils/iscsiadm.py @@ -96,7 +96,7 @@ def discovery(ipaddr): The list of iSCSI qualified names discovered. """ if not is_ip_reachable(ipaddr): - _iscsi_logger.debug('Given IP %s is not reachable.', ipaddr) + _iscsi_logger.warning('Given IP is not reachable.') return [] try: with open(os.devnull, 'w') as dev_null: diff --git a/lib/oci_utils/kvm/virt.py b/lib/oci_utils/kvm/virt.py index 4d39aab8..5e8285d6 100644 --- a/lib/oci_utils/kvm/virt.py +++ b/lib/oci_utils/kvm/virt.py @@ -7,31 +7,29 @@ """ Python wrapper around libvirt. """ -import logging -import os import subprocess -import tempfile -import time +import logging from xml.etree import ElementTree from xml.etree.ElementTree import Element from xml.etree.ElementTree import SubElement - +import tempfile +import os import libvirt from netaddr import IPNetwork - -from ..impl import IP_CMD, SUDO_CMD, PARTED_CMD, MK_XFS_CMD, print_choices, VIRSH_CMD, LSBLK_CMD +from ..impl import IP_CMD, SUDO_CMD, PARTED_CMD, MK_XFS_CMD, print_choices, VIRSH_CMD, LSBLK_CMD, IF_NAME_PREFIX from ..impl import sudo_utils -from ..impl.init_script_helpers import SystemdServiceGenerator -from ..impl.init_script_helpers import SystemdServiceManager +from ..impl.network_helpers import get_interfaces from ..impl.network_helpers import add_route_table from ..impl.network_helpers import delete_route_table -from ..impl.network_helpers import get_interfaces -from ..impl.network_helpers import remove_firewall_rule from ..impl.network_helpers import remove_static_ip_routes from ..impl.network_helpers import remove_static_ip_rules +from ..impl.network_helpers import remove_firewall_rule from ..impl.virt import sysconfig, virt_check, virt_utils from ..metadata import InstanceMetadata +from ..impl.init_script_helpers import SystemdServiceGenerator +from ..impl.init_script_helpers import SystemdServiceManager + _logger = logging.getLogger('oci-utils.kvm.virt') @@ -152,16 +150,16 @@ def find_unassigned_vf_by_phys(phys, domain_interfaces, desired_mac, vfs_blackli tuple The virtual function if found, None,None otherwise. """ - _logger.debug('find_unassigned_vf_by_phys called for (phys=%s,domain_interfaces=%s,desired_mac=%s,blacklist=%s)', - phys, domain_interfaces, desired_mac, vfs_blacklist) + _logger.debug('find_unassigned_vf_by_phys called for (phys=%s,domain_interfaces=%s,desired_mac=%s,blacklist=%s)' % + (phys, domain_interfaces, desired_mac, vfs_blacklist)) configured = sysconfig.read_network_config() - _logger.debug('configured interfaces are : %s', configured) + _logger.debug('configured interfaces are : %s' % configured) ifaces = get_interfaces() - _logger.debug('all interfaces are : %s', ifaces) + _logger.debug('all interfaces are : %s' % ifaces) virt_fns = ifaces[phys].get('virtfns', {}) - _logger.debug('virt_fns for given phys : %s', virt_fns) + _logger.debug('virt_fns for given phys : %s' % virt_fns) vfs = {virt_fns[v]['mac']: (virt_fns[v]['pci_id'], v) for v in virt_fns} - _logger.debug('vfs for given phys : %s', vfs) + _logger.debug('vfs for given phys : %s' % vfs) # First, remove entries where the mac address is configured via sysconfig for c in configured: @@ -173,11 +171,11 @@ def find_unassigned_vf_by_phys(phys, domain_interfaces, desired_mac, vfs_blackli # Configured interfaces with zero as a mac address are almost # certainly loopback interfaces of some variety. Not suitable # for a VM to use. - _logger.debug('discard [%s] because mac == "00:00:00:00:00:00"', str(c)) + _logger.debug('discard [%s] because mac == "00:00:00:00:00:00"' % str(c)) continue vf = vfs.get(mac) if vf: - _logger.debug('configured - discard vfs[%s] = %s', mac, vfs[mac]) + _logger.debug('configured - discard vfs[%s] = %s' % (mac, vfs[mac])) del vfs[mac] # Next, remove entries where the mac address is already in use manually @@ -185,12 +183,12 @@ def find_unassigned_vf_by_phys(phys, domain_interfaces, desired_mac, vfs_blackli for mac in i: vf = vfs.get(mac) if vf: - _logger.debug('mac found for domain %s domain_interfaces - discard vfs[%s] = %s', d, mac, vfs[mac]) + _logger.debug('mac found for domain %s domain_interfaces - discard vfs[%s] = %s' % (d, mac, vfs[mac])) del vfs[mac] _to_be_deleted = [] for mac in vfs.keys(): if vfs[mac] in vfs_blacklist: - _logger.debug('VFs found in black list - discard vfs[%s] = %s', mac, vfs[mac]) + _logger.debug('VFs found in black list - discard vfs[%s] = %s' % (mac, vfs[mac])) _to_be_deleted.append(mac) for _m in _to_be_deleted: @@ -203,7 +201,7 @@ def find_unassigned_vf_by_phys(phys, domain_interfaces, desired_mac, vfs_blackli prev = vfs.get(desired_mac) if prev: return prev - _logger.debug('post treatment, vfs = [%s], returning first one', str(vfs.values())) + _logger.debug('post treatment, vfs = [%s], returning first one' % str(vfs.values())) return list(vfs.values())[0] @@ -313,9 +311,9 @@ def test_vnic_and_assign_vf(ip_addr, free_vnics_ips, backlisted_vfs=()): The virtual network interface, the pci id, the virtual function id on success, False,False,False otherwise. """ - _logger.debug('test_vnic_and_assign_vf called with (%s,%s,%s)', ip_addr, free_vnics_ips, backlisted_vfs) + _logger.debug('test_vnic_and_assign_vf called with (%s,%s,%s)' % (ip_addr, free_vnics_ips, backlisted_vfs)) vnics = InstanceMetadata().refresh()['vnics'] - _logger.debug('vnics found in metadata: %s', vnics) + _logger.debug('vnics found in metadata: %s' % vnics) domains = virt_utils.get_domains_name() domain_interfaces = {d: virt_utils.get_interfaces_from_domain( virt_utils.get_domain_xml(d)) for d in domains} @@ -323,27 +321,27 @@ def test_vnic_and_assign_vf(ip_addr, free_vnics_ips, backlisted_vfs=()): # First see if the given ip address belongs to a vnic vnic = find_vnic_by_ip(ip_addr, vnics) if vnic is None: - _logger.error("%s is not the IP address of a VNIC.", ip_addr) + _logger.error("{} is not the IP address of a VNIC.", ip_addr) _print_available_vnics(free_vnics_ips) return False, False, False - _logger.debug('vnic found from IP : %s', vnic) + _logger.debug('vnic found from IP : %s' % vnic) # Next check that the ip address is not already assigned to a vm vnic_mac = vnic['macAddr'].lower() - _logger.debug('vnic found mac is %s', vnic_mac) + _logger.debug('vnic found mac is %s' % vnic_mac) dom = _find_vlan(vnic_mac, domain_interfaces) if dom: - _logger.error("%s is in use by \"%s\".", ip_addr, dom) + _logger.error("{} is in use by \"{}\".", ip_addr, dom) _print_available_vnics(free_vnics_ips) return False, False, False phys_nic = get_phys_by_index(vnic, vnics, get_interfaces()) - _logger.debug('physical intf found by index : %s', phys_nic) + _logger.debug('physical intf found by index : %s' % phys_nic) vf_pci_id, vf_num = find_unassigned_vf_by_phys(phys_nic, domain_interfaces, vnic_mac, backlisted_vfs) - _logger.debug('VF PCI id found [%s] VF number [%s]', vf_pci_id, vf_num) + _logger.debug('VF PCI id found [%s] VF number [%s]' % (vf_pci_id, vf_num)) if vf_pci_id is None: # This should never happen. There are always at least as many virtual # Functions as there are potential creatable vnics @@ -376,8 +374,8 @@ def create_networking(vf_device, vlan, mac, ip=None, prefix=None): The return value from starting the networking interface. """ - _logger.debug('create_networking called vf_device=%s,vlan=%s,mac=%s,ip=%s,prefix=%s', - vf_device, vlan, mac, ip, prefix) + _logger.debug('create_networking called vf_device=%s,vlan=%s,mac=%s,ip=%s,prefix=%s' % + (vf_device, vlan, mac, ip, prefix)) if vlan is not None: vf_cfg = sysconfig.make_vf(vf_device, mac) @@ -475,7 +473,7 @@ def get_interface_by_pci_id(pci_id, interfaces): pci_id : str The pci id. interfaces : dict - The name of the network interface if a match is found, + The name of of the network interface if a match is found, None otherwise. Returns @@ -523,12 +521,12 @@ def create(**kargs): try: _metadata = InstanceMetadata().refresh() except IOError as e: - _logger.error('Cannot fetch instance metadata: %s', str(e)) + _logger.error("Cannot fetch instance metadata: %s" % str(e)) return 1 _instance_shape = _metadata['instance']['shape'] _is_bm_shape = _instance_shape.startswith('BM') - _logger.debug('Instance shape is [%s]', _instance_shape) + _logger.debug('Instance shape is [%s]' % _instance_shape) if not virt_check.validate_kvm_env(_is_bm_shape): _logger.error("Server does not have supported environment for guest creation") @@ -538,7 +536,7 @@ def create(**kargs): _logger.error("Domain name \"{}\" is already in use.".format(kargs['name'])) return 1 - _logger.debug('Domain name to use [%s]', kargs['name']) + _logger.debug('Domain name to use [%s]' % kargs['name']) if kargs['root_disk']: _root_disk = virt_check.validate_block_device(kargs['root_disk']) @@ -557,7 +555,7 @@ def create(**kargs): '--disk', _disk_virt_install_args]) if _logger.isEnabledFor(logging.DEBUG): - _logger.debug('virt-install command [%s]', ' '.join(args)) + _logger.debug('virt-install command [%s]' % ' '.join(args)) if kargs['virtual_network']: for vn_name in kargs['virtual_network']: @@ -568,13 +566,13 @@ def create(**kargs): if _logger.isEnabledFor(logging.DEBUG): _logger.debug('vNICs found') for _v in vnics: - _logger.debug(' [%s]', str(_v)) + _logger.debug(' [%s]' % str(_v)) interfaces = get_interfaces() if _logger.isEnabledFor(logging.DEBUG): for _i in interfaces: - _logger.debug('Interface [%s]', _i) - _logger.debug(' [%s]', str(interfaces[_i])) + _logger.debug('Interface [%s]' % _i) + _logger.debug(' [%s]' % str(interfaces[_i])) if _is_bm_shape: # sanity : verify primary vnic is not specified @@ -587,21 +585,21 @@ def create(**kargs): args.append('--hvm') free_vnic_ip_addrs = [] free_vnics = find_free_vnics(vnics, interfaces) - _logger.debug('Free vNIC ips : %s', str(free_vnics)) + _logger.debug('Free vNIC ips : %s' % str(free_vnics)) if not kargs['network']: try: free_vnic_ip_addrs.append(free_vnics.pop()) - _logger.debug('No network option specified, taking the first one: %s', free_vnic_ip_addrs) + _logger.debug('No network option specified, taking the first one: %s' % free_vnic_ip_addrs) except KeyError: _print_available_vnics(free_vnics) return 1 else: - _logger.debug('Network option specified: %s', kargs['network']) + _logger.debug('Network option specified: %s' % kargs['network']) free_vnic_ip_addrs = kargs['network'] _blacklisted_vfs = [] for free_vnic_ip_addr in free_vnic_ip_addrs: - _logger.debug('Checking vnic [%s] and find VF', free_vnic_ip_addr) + _logger.debug('Checking vnic [%s] and find VF' % free_vnic_ip_addr) vnic, vf, vf_num = test_vnic_and_assign_vf(free_vnic_ip_addr, free_vnics, _blacklisted_vfs) if not vnic: return 1 @@ -609,15 +607,15 @@ def create(**kargs): _blacklisted_vfs.append((vf, vf_num)) vf_dev = get_interface_by_pci_id(vf, interfaces) - _logger.debug('VF dev found %s', vf_dev) + _logger.debug('VF dev found %s' % vf_dev) if not create_networking(vf_dev, vnic['vlanTag'], vnic['macAddr']): _logger.debug('Networking creation has failed') destroy_networking(vf_dev, vnic['vlanTag']) return 1 args.append('--network') - args.append('type=direct,source={}.{},source_mode=passthrough,mac={},' - 'model=e1000'.format(vf_dev, vnic['vlanTag'], vnic['macAddr'])) + args.append('type=direct,source={}{},source_mode=passthrough,mac={},' + 'model=e1000'.format(IF_NAME_PREFIX, vnic['vlanTag'], vnic['macAddr'])) else: # VM shape case : vnic are used directly (no VF) # sanity : verify primary vnic is not specified @@ -633,7 +631,7 @@ def create(**kargs): if intf_name == vn_name: _mac_to_use = intf_info['mac'].upper() if _mac_to_use is None: - _logger.error('Cannot find MAC address for %s', vn_name) + _logger.error('Cannot find MAC address for %s' % vn_name) return 1 if _mac_to_use == primary_mac: _logger.error('Primary vNIC must not be selected') @@ -642,25 +640,25 @@ def create(**kargs): % (vn_name, _mac_to_use)) else: _logger.debug('no vnic specified, find one') - # have to find one free interface. i.e. not already used by a guest + # have to find one free interface. i.e not already used by a guest # and not the primary one. the VNICs returned by metadata service is sorted list - # i.e. the first one is the primary VNICs + # i.e the first one is the primary VNICs domains_nics = _get_intf_used_by_guest() - _logger.debug('NICs used by domains [%s]', domains_nics) + _logger.debug('NICs used by domains [%s]' % domains_nics) intf_to_use = None _mac_to_use = None for intf_name, intf_info in interfaces.items(): - # skip non-physical intf + # skip non physical intf if not intf_info['physical']: - _logger.debug('Skipping physical [%s]', intf_info) + _logger.debug('Skipping physical [%s]' % intf_info) continue # if used by a guest, skip it if intf_name in [list(m.values())[0] for m in list(domains_nics.values())]: - _logger.debug('skipping used by guest [%s]', intf_name) + _logger.debug('skipping used by guest [%s]' % intf_name) continue # if primary one (primary VNIC), skip it if vnics[0]['macAddr'].upper() == intf_info['mac'].upper(): - _logger.debug('Skipping primary [%s]', intf_info) + _logger.debug('Skipping primary [%s]' % intf_info) continue # we've found one intf_to_use = intf_name @@ -682,7 +680,7 @@ def create(**kargs): print("Autoconsole has been disabled. To view the console, issue 'virsh console {}'".format(kargs['name'])) if _logger.isEnabledFor(logging.DEBUG): - _logger.debug('Create: executing [%s]', ' '.join(args)) + _logger.debug('Create: executing [%s]' % ' '.join(args)) _logger.debug('Executing\n%s', args) virt_install = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -690,11 +688,11 @@ def create(**kargs): (_out, _err) = virt_install.communicate() _logger.debug('virt-install process terminated.') if virt_install.returncode != 0: - _logger.error('Creation failed: %s', _err.decode('utf-8')) + _logger.error('Creation failed: %s' % _err.decode('utf-8')) if _is_bm_shape and not kargs['virtual_network']: destroy_networking(vf_dev, vnic['vlanTag']) return 1 - _logger.debug('Creation succeed: %s', _out.decode('utf-8')) + _logger.debug('Creation succeed: %s' % _out.decode('utf-8')) return 0 @@ -707,10 +705,14 @@ def destroy(name, delete_disks): name : str The domain name. delete_disks : bool - Do we also delete to storage pool based disks? + Do we also delette to storage pool based disks ? + stop_it_first : boool + Do we shutdown the VM if it is running ? + gracefull : bool + Do we force the operation ? Returns ------- - int: + int 1 if domain does not exist or is running. Return value form virsh undefine. """ @@ -720,7 +722,7 @@ def destroy(name, delete_disks): _logger.error('Failed to open connection to qemu:///system') return 1 dom = libvirtConn.lookupByName(name) - if dom is None: + if dom == None: _logger.error('domain do not exists') return 1 @@ -742,10 +744,10 @@ def destroy(name, delete_disks): if len(net_intfs) > 0: vnet = net_intfs[0].findall('source')[0].get('network') if vnet: - _logger.debug('destroy: use of virtual network [%s] detected', vnet) + _logger.debug('destroy: use of virtual network [%s] detected' % vnet) _use_virtual_network = True except libvirt.libvirtError as e: - _logger.error('Failed to get domain information: %s', e.get_error_message()) + _logger.error('Failed to get domain information: %s' % e.get_error_message()) libvirtConn.close() return 1 @@ -762,13 +764,13 @@ def destroy(name, delete_disks): if file_as_source: _vol = virt_utils.find_storage_pool_volume_by_path(libvirtConn, file_as_source) if _vol: - _logger.debug('libvirt volume found [%s]', _vol.name()) + _logger.debug('libvirt volume found [%s]' % _vol.name()) try: _vol.wipe(0) _vol.delete(0) _logger.debug('libvirt volume deleted') except libvirt.libvirtError as e: - _logger.error('Cannot delete volume [%s]: %s', _vol.name(), str(e)) + _logger.error('Cannot delete volume [%s]: %s' % (_vol.name(), str(e))) libvirtConn.close() @@ -819,7 +821,7 @@ def create_netfs_pool(netfs_server, resource_path, name): pool.create() except libvirt.libvirtError as e: pool.undefine() - _logger.error('Failed to setup the pool: %s', e.get_error_message()) + _logger.error('Failed to setup the pool: %s' % e.get_error_message()) return 1 finally: conn.close() @@ -855,19 +857,12 @@ def create_fs_pool(disk, name): _new_part = "%s1" % disk if sudo_utils.call([MK_XFS_CMD, '-f', '-q', _new_part]): - _logger.error('Failed to make xfs filesystem on new partition') + _logger.error('Failed to make xfs filesystem on new prtition') return 1 # grab the uuid of the device - _uuid = '' - for _ in range(5): - _uuid = sudo_utils.call_output([LSBLK_CMD, '--output', 'uuid', '--noheadings', _new_part]) - _uuid = _uuid.decode().strip() - if _uuid: - break - time.sleep(1) - if not _uuid: - return 1 + _uuid = sudo_utils.call_output([LSBLK_CMD, '--output', 'uuid', '--noheadings', _new_part]) + _uuid = _uuid.decode().strip() if sudo_utils.call([VIRSH_CMD, '--quiet', 'pool-define-as', '--name=%s' % name, '--type=fs', @@ -924,7 +919,7 @@ def create_virtual_network(**kargs): try: _metadata = InstanceMetadata().refresh() except IOError as e: - _logger.error("Cannot fetch instance metadata: %s", str(e)) + _logger.error("Cannot fetch instance metadata: %s" % str(e)) return 1 _instance_shape = _metadata['instance']['shape'] @@ -933,7 +928,7 @@ def create_virtual_network(**kargs): # get the given IP used to find vNIC to use _vnic_ip_to_use = kargs['network'] - _logger.debug('In create_virtual_network, given IP : %s ', _vnic_ip_to_use) + _logger.debug('In create_virtual_network, given IP : %s ' % _vnic_ip_to_use) # get all vNIC of the current system _all_vnics = _metadata['vnics'] @@ -951,10 +946,10 @@ def create_virtual_network(**kargs): if not vnic: _logger.debug('Choosen vNIC is not free') return 1 - _logger.debug('Ready to write network configuration for (%s, %s, %s)', vnic, vf, vf_num) + _logger.debug('Ready to write network configuration for (%s, %s, %s)' % (vnic, vf, vf_num)) vf_dev = get_interface_by_pci_id(vf, _all_system_interfaces) - _logger.debug('vf device for %s: %s', vf, vf_dev) + _logger.debug('vf device for %s: %s' % (vf, vf_dev)) if not create_networking(vf_dev, vnic['vlanTag'], vnic['macAddr'], @@ -972,16 +967,16 @@ def create_virtual_network(**kargs): vnic = v break if vnic is None: - _logger.error('vNIC with address [%s] not found', _vnic_ip_to_use) + _logger.error('vNIC with address [%s] not found' % _vnic_ip_to_use) return None for intf_name, attrs in _all_system_interfaces.items(): if attrs['mac'].upper() == vnic['macAddr'].upper() and attrs['physical']: vf_dev = intf_name if vf_dev is None: - _logger.error('Cannot find network interface matching vNIC with ip [%s]', _vnic_ip_to_use) + _logger.error('Cannot find network interface matching vNIC with ip [%s]' % _vnic_ip_to_use) return 1 - _logger.debug('Device for nework %s', vf_dev) + _logger.debug('Device for nework %s' % vf_dev) if not create_networking(vf_dev, None, @@ -995,7 +990,7 @@ def create_virtual_network(**kargs): _logger.debug('Networking succesfully created') # define a routing table for the new VF. - _logger.debug('Add new routing table [%s]', vf_dev) + _logger.debug('Add new routing table [%s]' % vf_dev) add_route_table(vf_dev) # deduce KVMnetwork @@ -1029,7 +1024,7 @@ def create_virtual_network(**kargs): dhcp = SubElement(ip, 'dhcp') SubElement(dhcp, 'range', start=kargs['ip_start'], end=kargs['ip_end']) - _logger.debug('Defining network as [%s]', ElementTree.tostring(netXML).decode('utf-8')) + _logger.debug('Defining network as [%s]' % ElementTree.tostring(netXML).decode('utf-8')) tf = tempfile.NamedTemporaryFile(mode='w', delete=False) os.chmod(tf.name, 0o644) @@ -1038,7 +1033,7 @@ def create_virtual_network(**kargs): (code, _, stderr) = sudo_utils.execute([VIRSH_CMD, '--quiet', 'net-define', tf.name]) if code != 0: - _logger.error('Failed to define the network: %s', stderr) + _logger.error('Failed to define the network: %s' % stderr) os.remove(tf.name) delete_route_table(vf_dev) destroy_networking(vf_dev, vnic['vlanTag']) @@ -1051,7 +1046,7 @@ def create_virtual_network(**kargs): try: kvm_sysd_svc.generate() except Exception as e: - _logger.error('Failed to generate the init script : %s', str(e)) + _logger.error('Failed to generate the init script : %s' % str(e)) delete_route_table(vf_dev) destroy_networking(vf_dev, vnic['vlanTag']) return 1 @@ -1063,8 +1058,6 @@ def create_virtual_network(**kargs): destroy_networking(vf_dev, vnic['vlanTag']) return 1 - return 0 - def delete_virtual_network(**kargs): """ @@ -1084,13 +1077,13 @@ def delete_virtual_network(**kargs): """ libvirtConn = libvirt.open(None) if libvirtConn is None: - _logger.error('Cannot find network named [%s]', kargs['network_name']) + _logger.error('Cannot find network named [%s]' % kargs['network_name']) return 1 net = None try: net = libvirtConn.networkLookupByName(kargs['network_name']) except libvirt.libvirtError: - _logger.error('Cannot find network named [%s]', kargs['network_name']) + _logger.error('Cannot find network named [%s]' % kargs['network_name']) return 1 root = ElementTree.fromstring(net.XMLDesc()) diff --git a/lib/oci_utils/metadata.py b/lib/oci_utils/metadata.py index 6ddf6c5c..d50c20c0 100644 --- a/lib/oci_utils/metadata.py +++ b/lib/oci_utils/metadata.py @@ -413,6 +413,7 @@ def _filter(self, metadata, keys): return None return new_metadata if isinstance(metadata, tuple): + # _GT_ filtered_tuple = [filter_results(x, keys) for x in metadata] filtered_tuple = [(x, keys) for x in metadata] for a in filtered_tuple: if a is not None: diff --git a/lib/oci_utils/migrate/reconfigure_network.py b/lib/oci_utils/migrate/reconfigure_network.py index 2a48d5ef..12a2df9a 100644 --- a/lib/oci_utils/migrate/reconfigure_network.py +++ b/lib/oci_utils/migrate/reconfigure_network.py @@ -1,6 +1,6 @@ # oci-utils # -# Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. # Licensed under the Universal Permissive License v 1.0 as shown # at http://oss.oracle.com/licenses/upl. diff --git a/lib/oci_utils/vnicutils.py b/lib/oci_utils/vnicutils.py index dc590697..3f49bdeb 100644 --- a/lib/oci_utils/vnicutils.py +++ b/lib/oci_utils/vnicutils.py @@ -13,6 +13,7 @@ from . import cache from .impl import IP_CMD +from .impl import IF_NAME_PREFIX from .impl import network_helpers as NetworkHelpers from .impl import sudo_utils from .impl.network_interface import NetworkInterfaceSetupHelper, _intf_dict @@ -386,7 +387,7 @@ def auto_config(self, sec_ip, deconfigured=True): if ip not in _intf['MISSING_SECONDARY_IPS']: _intf['MISSING_SECONDARY_IPS'].append(ip) - # + # GT _logger.debug('Auto config interface %s %s', _intf['ADDR'], _intf['CONFSTATE']) if _intf['CONFSTATE'] == 'ADD': if deconfigured: @@ -401,7 +402,7 @@ def auto_config(self, sec_ip, deconfigured=True): _intf['MISSING_SECONDARY_IPS'] = _intf['SECONDARY_ADDRS'] if _intf['CONFSTATE'] == 'DELETE': _all_to_be_deconfigured.append(_intf) - # + # GT # if called by the ocid service, the interfaces which were unconfigured by the oci-network-config # unconfigure command should not be touched; only an oci-network-config configure command will change this; # the ocid service calls auto_config with deconfigured=False. @@ -889,12 +890,10 @@ def get_network_config(self): CONFSTATE 'uncfg' indicates missing IP config, 'missing' missing VNIC, 'excl' excluded (-X), '-' hist configuration match oci vcn configuration ADDR IP address - SPREFIX4 subnet CIDR IPV4 prefix - SBITS4 subnet mask IPV4 bits - VIRTRT4 virtual router IPV4 address - SPREFIX6 subnet CIDR IPV6 prefix - SBITS6 subnet mask IPV6 bits - VIRTRT6 virtual router IPV6 addressNS namespace (if any) + SPREFIX4 subnet CIDR prefix + SBITS4 subnet mask bits + VIRTRT4 virtual router IP address + NS namespace (if any) IND interface index (if BM) IFACE interface (underlying physical if VLAN is also set) VLTAG VLAN tag (if BM) @@ -997,7 +996,7 @@ def _auto_config_intf_routing(self, net_namespace_info, intf_infos): _intf_to_use = intf_infos['IFACE'] if self._metadata['instance']['shape'].startswith('BM') and intf_infos['VLTAG'] != "0": # in that case we operate on the VLAN tagged intf no - _intf_to_use = '%sv%s' % (intf_infos['IFACE'], intf_infos['VLTAG']) + _intf_to_use = '%sv%s' % (IF_NAME_PREFIX, intf_infos['VLTAG']) if net_namespace_info: _logger.debug("Default ipv4 route add") diff --git a/libexec/oci-image-cleanup b/libexec/oci-image-cleanup index 07bc1896..e9129033 100755 --- a/libexec/oci-image-cleanup +++ b/libexec/oci-image-cleanup @@ -332,7 +332,7 @@ cleanup() backup_and_delete "/var/log/*" -c 1 # oracle-cloud-init directiry must not be deleted for file in `find /var/log -regex ".+[\.\-]+[0-9]+" -and ! -name oracle-cloud-agent 2>/dev/null`; do - plan rm -f $file + plan rm -rf $file done # Scrub Chrony Cleanup plan 'echo -e "\nScrubbing /etc/chrony.keys..."' @@ -370,7 +370,7 @@ cleanup() fi # Purge cloud-init data plan 'echo -e "\nClearing cloud-init data..."' - backup_and_delete "/var/lib/cloud/*" + backup_and_delete "/var/lib/cloud/*" -x "oci.sh" backup_and_delete "/var/lib/cloud/instance" backup_and_delete "/var/lib/cloud/instances" diff --git a/libexec/oci-image-expand b/libexec/oci-image-expand new file mode 100644 index 00000000..909b05e7 --- /dev/null +++ b/libexec/oci-image-expand @@ -0,0 +1,678 @@ +#!/bin/bash + +# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown +# at http://oss.oracle.com/licenses/upl. + +############################################################################### +# +# Name: oci-image-expand +# Description: script to expand (unminimize) an OL9 minimal image +# User selects which non-default options to add (those requiring reboot) +# Default added functions include systemd services, diagnostic packages and cloud configuration settings. +# User selectable functions (requiring reboot) -- SELinux, Kdump, Ksplice, iSCSI. +# If a reboot is required, user will be prompted +# +############################################################################### + +# global variables +return_val=0 +SELINUX_SELECTED="NO" +KDUMP_SELECTED="NO" +KSPLICE_SELECTED="NO" +REBOOT_REQUIRED="NO" +SELINUX_ENABLED="NO" +KDUMP_ENABLED="NO" +KSPLICE_ENABLED="NO" +declare -a options=('All reboot options' 'Enable SELinux' 'Enable Kdump' 'Enable Ksplice') +# set a default set of initially chosen options -- start with no reboot options selected +declare -a choices=( " " " " " " " " ) +ERROR=" " + +usage() { +cat <&2; + usage; + exit 99 + ;; + esac +done + +# use the bash logger facility to log information and error messages +log "INFO: oci-image-expand START $(date):" + +# this script is only valid for OL9 instances and above +os_version=0 +if [ -f /etc/os-release ]; then + os_string=$(grep -w VERSION /etc/os-release | awk -F "\"" '{print $2}') + log "INFO: Obtained $os_string from /etc/os-release" + echo "INFO: Obtained OS version string $os_string from /etc/os-release" + if [[ "$os_string" == "9."* || "$os_string" == "9"* ]]; then + os_version=9 + elif [[ "$os_string" == "8."* || "$os_string" == "8"* ]]; then + os_version=8 + elif [[ "$os_string" == "7."* || "$os_string" == "7"* ]]; then + os_version=7 + elif [[ "$os_string" == "6."* ]]; then + os_version=6 + fi +fi + +if [ $os_version == 0 ]; then + log "INFO: Getting OS version via uname -mrs" + kernel_version=$(uname -mrs) + if [[ "$kernel_version" == *"el9"* ]]; then + os_version=9 + elif [[ "$kernel_version" == *"el8"* ]]; then + os_version=8 + elif [[ "$kernel_version" == *"el7"* ]]; then + os_version=7 + elif [[ "$kernel_version" == *"el6"* ]]; then + os_version=6 + fi +fi + +if [ $os_version == 0 ]; then + log "ERROR: Could not obtain valid OS version. Exiting." + echo "ERROR: Could not obtain valid OS version. Exiting." + exit 20 +fi + +if [[ "$os_version" -lt 9 ]]; then + log "ERROR: This script is only valid on instances running OL9, current version is $os_version" + echo "ERROR: This script is only valid on instances running OL9, current version is $os_version" + exit 21 +fi + +# at present, there is only an OL9 minimal image for x86_64 shapes +# so, we check for ARM shapes -- aarch64 -- and print warning and exit if so +processor_type=$(uname -p) +log "INFO: Obtained processor type $processor_type using uname -p output." +echo "INFO: Obtained processor type $processor_type using uname -p output." +if [ "$processor_type" == "aarch64" ]; then + log "ERROR: This script is only valid on x86_64 architectures, not on $processor_type, exiting." + echo "ERROR: This script is only valid on x86_64 architectures, not on $processor_type, exiting." + exit 22 +fi + +# this script is only valid for OL9 minimal images, so check for that +# under dnf installed groups label "Installed Environment Groups:" +# will be "Minimal Install" (perhaps with some leading spaces) +log "INFO: Checking to see if this is an OL Minimal image instance." +echo "INFO: Checking to see if this is an OL Minimal image instance." +min_image_str=$(dnf group list --installed | grep "Minimal Install" | sed -e 's/^[[:space:]]*//') +if [ ! "$min_image_str" == "Minimal Install" ]; then + log "ERROR: This script is only valid on OL9 minimal images, exiting." + echo "ERROR: This script is only valid on OL9 minimal images, exiting." + exit 23 +fi + +# this script requires sudo privileges for calls to systemctl, yum, etc. +# so check to see if those privileges exist for this user, else exit +log "INFO: Checking to see if the current user has sudo privileges." +echo "INFO: Checking to see if the current user has sudo privileges." +sudo -n true +rc=$? +if [ "$rc" -ne 0 ]; then + log "ERROR: This script requires the user to have sudo privileges, exiting." + echo "ERROR: This script requires the user to have sudo privileges, exiting." + exit 24 +fi + +select_options + +apply_options + +# if at least one rebootable option was selected, offer a choice of when to reboot +printf "\n oci-image-expand: All selected options have now been applied.\n\n" +if [[ $REBOOT_REQUIRED == "YES" ]]; then + printf "A reboot is required to enable and activate all restored services\n" + while true; do + + read -r -p "Do you wish to reboot now? (y/n) " yn + + case $yn in + [yY] ) echo "Proceeding to reboot ..." + log "INFO: oci-image-expand END rebooting now $(date):" + break;; + [nN] ) echo "Exiting ... please reboot the system to restore full functionality.;" + log "INFO: oci-image-expand END reboot required to restore full functionality $(date):" + exit 0;; + * ) echo invalid response;; + esac + + done + # as reboot quickly disables rsyslogd, add a short sleep for log message to be committed + sleep 5 + sudo reboot +else + log "INFO: oci-image-expand END $(date):" + echo "oci-image-expand execution complete -- reboot not needed at this time." + exit 0 +fi + +# end MAIN diff --git a/libexec/oci-utils-config-helper b/libexec/oci-utils-config-helper index 14009bf5..b5cea961 100755 --- a/libexec/oci-utils-config-helper +++ b/libexec/oci-utils-config-helper @@ -13,3 +13,60 @@ _PY_CMD=oci_show_config_main.py exec ${_PY3} ${s_dir}/${_PY_CMD} + + +# __GT__ kept this for reference, for now +# +# import json +# import sys +# +# import oci_utils.oci_api +# +# debug = False +# +# +# def response(status, **kwargs): +# """ +# Send a json formatted response to stdout, jdata is already json formatted. +# +# Parameters +# ---------- +# status: str +# The status. +# kwargs: key,value +# The data to convert to json. +# +# Returns +# ------- +# str +# The json formatted version of **kwargs +# """ +# resp = {'status': status} +# for key, val in kwargs.items(): +# resp[key] = val +# sys.stdout.write(json.dumps(resp) + '\n') +# sys.stdout.flush() +# +# +# def main(): +# """ +# Main program +# +# Returns +# ------- +# int +# 0 +# """ +# try: +# session = oci_utils.oci_api.OCISession( +# authentication_method=oci_utils.oci_api.DIRECT) +# except Exception as e: +# response('ERROR', data=str(e)) +# return 1 +# +# response('OK', data=session.oci_config) +# return 0 +# +# +# if __name__ == "__main__": +# sys.exit(main()) diff --git a/man/man1/oci-attached-volumes.1 b/man/man1/oci-attached-volumes.1 deleted file mode 100644 index e08f8b5c..00000000 --- a/man/man1/oci-attached-volumes.1 +++ /dev/null @@ -1,83 +0,0 @@ -.\" Process this file with -.\" groff -man -Tascii oci-attached-volumes.1 -.\" -.\" Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. -.\" Licensed under the Universal Permissive License v 1.0 as shown -.\" at http://oss.oracle.com/licenses/upl. -.\" -.TH OCI-ATTACHED-VOLUMES 1 "SEPTEMBER 2022" Linux "User Manuals" -.SH NAME -oci-attached-volumes \- Collect data of iscsi volumes attached to this instance. -.SH SYNOPSIS -.B oci-attached-volumes -usage - -.B oci-attached-volumes -attached [-h|--help] [-i|--iqn] [-a|--all] [-o|--output-mode MODE] - -.B oci-attached-volumes -all [-h|--help] [-o|--output-mode MODE] - -.B oci-attached-volumes -uses the services of the python3 -.B oci-sdk -package. - -.SH DESCRIPTION -If the Oracle Cloud Infrastructure services authorisation allows listing the block volumes, -.B oci-attached-volumes -can show more details on the attached and other volumes. Otherwise only the -.B iqn, ip address and port -are displayed. More, if there is no authorisation to list all block volumes, the -.B attached option falls back to - -.B oci-attached-volume -attached --iqn - -and the -.B all -option shows a message and exits. - -.B oci-attached-volumes -must be run with root privileges, either as user root or using -.BR sudo(8). - - -.TP -oci-attached-volumes attached -Show data on attached block volumes. -.RS -.IP -i,--iqn -Displays the ipaddress, the port and the iqn of the attached block volumes -.IP -a,--all -Displays the ipaddress, the port, the iqn, the display name, the create date and the volume of the attached block volumes. The -flags -.B --iqn -and -.B --all -are mutually exclusive. -.IP --output-mode={json,text,parsable} -Display list of the attached block volumes using json format, simple text or using parsable output. -(default is text) -.RE -.TP -oci-attache-volume all -Show data on all block volumes in the availability domain. -.RS -.IP --output-mode={json,text,parsable} -Display list of block volumes using json format, simple text or using parsable output -(default is text) - - -.SH EXAMPLES -.PP -.nf -.RS -sudo oci-attached-volumes attached --iqn --output-mode=parsable -.RE -.PP -.nf -.RS -sudo oci-attached-volumes all --output-mode=text -.RE -.fi diff --git a/man/man1/oci-notify.1 b/man/man1/oci-notify.1 index ca73bbe7..d92f1b94 100644 --- a/man/man1/oci-notify.1 +++ b/man/man1/oci-notify.1 @@ -10,9 +10,6 @@ oci-notify - Send a message and data to a Oracle Cloud Infrastructure notification service. .SH SYNOPSIS -.B oci-notify -usage - .B oci-notify config OCID_TOPIC @@ -65,7 +62,7 @@ must be run with root privileges, either as user root or using .B sudo(8). .SH OPTIONS -.IP "oci-notify usage" +.IP "oci-notify --help" usage: oci-notify-main.py [-h] {config,message} ... This utility assists with sending messages to an Oracle Cloud Infrastructure @@ -75,8 +72,7 @@ number of chunks is limited to 10. The message file can be a flat file, a url or a string. See the manual page for more information. positional arguments: - {usage,config,message} - usage Displays usage + {config,message} config Configure the notification server. message Send a message. diff --git a/setup.py b/setup.py index 885924fa..f5d2d8ee 100644 --- a/setup.py +++ b/setup.py @@ -413,7 +413,6 @@ def run(self): 'man/man1/oci-instanceid.1', 'man/man1/oci-compartmentid.1', 'man/man1/oci-volume-data.1', - 'man/man1/oci-attached-volumes.1', ]), (os.path.join(sys.prefix, "share", "man", "man5"), ['man/man5/oci-utils.conf.d.5', @@ -444,7 +443,6 @@ def run(self): 'bin/oci-instanceid', 'bin/oci-test-ip-auth', 'bin/oci-volume-data', - 'bin/oci-attached-volumes', ], classifiers=[ "Development Status :: 3 - Alpha", diff --git a/tests/automation/Makefile b/tests/automation/Makefile deleted file mode 100644 index a55a29f1..00000000 --- a/tests/automation/Makefile +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for oci-utils-automation -# -# -TARGET=oci-utils-automation -CONFIGDIR=git_repo/tests/automation/configuration -# CONFIGDIR=configuration -DOCFILES=$(CONFIGDIR)/README.txt $(CONFIGDIR)/BUILD.txt -USRFILES=$(CONFIGDIR)/oci-utils-automation.repo-7 $(CONFIGDIR)/oci-utils-automation.repo-8 -DISTRIBUTIONS=OL7 OL8 -GPGFILES=$(CONFIGDIR)/RPM-GPG* -RELDATA=$(CONFIGDIR)/oci-utils-automation.spec -# -VER=$(shell sed -n "/Version:/p" ${RELDATA} |sed -e 's/Version:\ *//') -REL=$(shell sed -n "/Release:/p" ${RELDATA} |sed -e 's/Release:\ *//'| sed -e 's/\%.*//') -VERSION=${VER}-${REL} -VERSIONRPM=${VER} -TMPDIR="oci-utils-automation-$(VERSIONRPM)" -NOW=$(shell date +%d%m%Y_%H%M) -# -DESTDIR=/var/www/html/channel_rpms/$(USER) -YUMDIR=/var/www/html/yum/$(USER) -ISODIR=/var/www/html/isos -# -MKDIR=-mkdir -p -SUMKDIR=sudo mkdir -p -SURMDIR=sudo rm -rf -CHMODEXEC=chmod 755 -CURL=curl -SUCHOWN=sudo chown -R -CHANGEDIR=cd -WRITE=@echo -INSTALL=install -m 644 -t ${DESTDIR} -REMOVE=@-rm -f -RECREM=@-rm -rf -COPYR=cp -a --parents -COPYA=cp -a -COPYANOFAIL=-cp -a -BACKUP=cp --preserve -TAR=tar -czvf -RPMBUILD=rpmbuild -v -ba -THISDIR=${PWD} -SED=sed -i -GREP=egrep -AWKFOR=awk -F: '{print $$4}' -CREATEREPO=createrepo -q -c -THISIP=$(shell hostname -I|tr -d '[:space:]') -THISGROUP=$(shell ${GREP} $(USER): /etc/passwd | $(AWKFOR)) -# -# help -# -.PHONY: help -help: - $(WRITE) "help info:" - $(WRITE) " for the install of $(TARGET) version ${VERSION}" - $(WRITE) " make help" - $(WRITE) " make showversion" - $(WRITE) " make distro" - $(WRITE) " make directorystructure" - $(WRITE) " make rpms" - $(WRITE) " make repos" - $(WRITE) " make publish" - $(WRITE) " make clean" - $(WRITE) " for adding rpm $(RPM) to repository for distro ${DISTR}" - $(WRITE) " make copyrpm RPM=[path|url to rpm] DISTRO=[OL7|OL8]" - $(WRITE) " make isodir" - $(WRITE) " make cleanrepo" - -# -# version info -.PHONY: showversion ${SOURCEFILES} -showversion: - $(WRITE) "version of $(TARGET) source is $(VERSION)" -# -# -# create tarball and update repofiles with $USER -distro: $(USRFILES) - ${RECREM} $(TMPDIR) - ${MKDIR} $(TMPDIR) - ${SED} s/_UUUU_/$(USER)/ $^ - ${SED} s/_IPIP_/$(THISIP)/ $^ - ${COPYR} ${USRFILES} $(TMPDIR) - $(COPYA) ${RELDATA} $(TMPDIR) - $(COPYA) Makefile $(TMPDIR) - $(COPYA) ${DOCFILES} $(TMPDIR) - $(COPYA) ${GPGFILES} $(TMPDIR) - ${TAR} $(TARGET)-$(VERSIONRPM).tar.gz $(TMPDIR)/* - ${RECREM} $(TMPDIR)/ - $(WRITE) "Distribution package created as $(TARGET)-$(VERSION).tar.gz" -# -# -# create directories -directorystructure: distro - ${MKDIR} rpmbuild/RPMS/noarch - ${MKDIR} rpmbuild/SOURCES - ${MKDIR} rpmbuild/SRPMS - ${MKDIR} rpmbuild/RPMS - ${MKDIR} rpmbuild/BUILD - ${MKDIR} rpmbuild/BUILDROOT - ${MKDIR} rpmbuild/SPECS - $(COPYA) $(TARGET)-$(VERSIONRPM).tar.gz rpmbuild/SOURCES - $(COPYA) $(CONFIGDIR)/$(TARGET).spec rpmbuild/SPECS - $(WRITE) "created directory structure" -# -# -# buildrpms -rpms: directorystructure - ${RPMBUILD} --define '_topdir $(PWD)/rpmbuild' rpmbuild/SPECS/$(TARGET).spec --define "dist .el7" - ${RPMBUILD} --define '_topdir $(PWD)/rpmbuild' rpmbuild/SPECS/$(TARGET).spec --define "dist .el8" - $(WRITE) "rpms build" -# -# -# repos -repos: - $(foreach distro,$(DISTRIBUTIONS), ${SUMKDIR} $(YUMDIR)/$(distro)/x86_64/getPackage;) - $(foreach distro,$(DISTRIBUTIONS), ${SUCHOWN} $(USER):${THISGROUP} $(YUMDIR)/$(distro);) -# -# -# publish -publish: repos rpms - $(WRITE) "${DESTDIR}" - ${SUMKDIR} ${DESTDIR} - sudo $(COPYA) rpmbuild/RPMS/noarch/* ${DESTDIR} - sudo chcon -R -t httpd_sys_content_t $(dir $(DESTDIR)) - $(WRITE) "moved rpms to ${DESTDIR}" -# -# -# clean -clean: - ${RECREM} rpmbuild - ${REMOVE} oci-utils-automation*tar.gz - $(WRITE) "cleaned up" -# -# -# copy rpm to repo -copyrpm: repos -ifdef RPM - $(WRITE) $(RPM) -ifdef DISTRO - $(WRITE) $(DISTRO) -ifneq (,$(findstring http, $(RPM))) - $(WRITE) "$(RPM) is a URL" - $(CURL) $(RPM) --output $(YUMDIR)/$(DISTRO)/x86_64/getPackage/$(notdir $(RPM)) -else - $(WRITE) "$(RPM) is a FILE" - $(COPYA) $(RPM) $(YUMDIR)/$(DISTRO)/x86_64/getPackage -endif - $(CREATEREPO) $(YUMDIR)/$(DISTRO)/x86_64/.cache $(YUMDIR)/$(DISTRO)/x86_64 - sudo chcon -R -t httpd_sys_content_t $(dir $(YUMDIR)/$(DISTRO)) -else - $(WRITE) "DISTRO missing" -endif -else - $(WRITE) "RPM missing" -endif -# -# -# make directory for storing iso's with respect to oci-kvm rpm and oci-kvm image tests -isodir: - ${SUMKDIR} $(ISODIR) - sudo chcon -R -t httpd_sys_content_t $(ISODIR) -# -# -# clean up repositories -cleanrepo: - $(foreach distro,$(DISTRIBUTIONS), ${SURMDIR} $(YUMDIR)/$(distro)/x86_64/getPackage;) \ No newline at end of file diff --git a/tests/automation/__init__.py b/tests/automation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/automation/configuration/BUILD.txt b/tests/automation/configuration/BUILD.txt deleted file mode 100644 index a6cf6559..00000000 --- a/tests/automation/configuration/BUILD.txt +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for oci-utils-automation -# - -as user: - -update files, sources, spec, gpg keys -run - make help - shows help info - make showversion - shows spec versiondata - make distro - creates compressed tarball - make directorystructure - creates the directorystructure for building the rpms - make rpms - builds the rpms - make repos - creates the repo directories - make publish - copies the rpms to the destination, the default is /var/www/html/channel_rpms/$USER - the default destination is in the webserver area. - make clean - - make copyrpm RPM=[path|url to rpm] DISTRO=[OL7|OL8] - copies the rpm to the appropriate repository. - make cleanrepo - -current supported distributions: - .el7 - .el8 diff --git a/tests/automation/configuration/README.txt b/tests/automation/configuration/README.txt deleted file mode 100644 index d3d38423..00000000 --- a/tests/automation/configuration/README.txt +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for oci-utils-automation -# -=================================================== -oci-utils-automation - For Oracle Internal Use Only -=================================================== -The oci-utils-automation rpms define the repofiles for -accessing rpms to test and creates the repository -directories if they do not exist yet. - -usage: -- pull the software tree -- change directory to the software root -- run 'make publish' -- run 'make clean' -- run 'make copyrpm RPM=[path|url] DISTRO=[OL7|OL8]' -- run 'make cleanrepo' - -copy rpms to the repositories: - make copyrpm RPM= DISTRO= diff --git a/tests/automation/configuration/RPM-GPG-KEY-oracle-7 b/tests/automation/configuration/RPM-GPG-KEY-oracle-7 deleted file mode 100644 index 38f13224..00000000 --- a/tests/automation/configuration/RPM-GPG-KEY-oracle-7 +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.5 (GNU/Linux) - -mQENBEwtJWoBCACpiY2rGA6T0ceBi92X88/QclytVBjtDRohOVzs3pmIPh3ULqsW -G323nmyKbKQBBSjh9OnuO9Y09VG8mzr/w9YV0Ix4cI9/HDTERZ2+TR5u+VNn5J5h -yvwQSN/FEK6oH2+mz7O0yUNleN7UltR4MOEkHIoAhIvv+1AQQKN3OM8oalz+3gv/ -zz9rAoQczQzT7QWOtBrsRMZgBrKXY/TpJrpVSO3Hx8CnbhKGtLxCCrxZ5v7hh1ht -3CRAr2+h5bDA9KP6vBZWKEs7NgcvtZFDY6EJc7AoApr3phX9hHE2+snTxe82DkFT -uA69C8wLyjPCoSy+tcaCqJKOZelNy9RN/WKRABEBAAG0RE9yYWNsZSBPU1MgZ3Jv -dXAgKE9wZW4gU291cmNlIFNvZnR3YXJlIGdyb3VwKSA8YnVpbGRAb3NzLm9yYWNs -ZS5jb20+iQE8BBMBAgAmAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AFAlNhkUEF -CSaOl9cACgkQcvl7dOxVHwNHFQf9G2ZI5ZH8T1VASvQteTyUR7uNgqXEbJhi9zZO -7EO26+wzkj9EGLmH1COdUApZ1cINsYfGGgUJT5mfcRV3yYZbwc4AZJbJe0z7C5Yu -ZLs5W0ryV4bzIqcWnVphIAOwmxMxIVGz8Cr1Dsyyal7ORgYzdfOppYetwtZ+J+Wn -/oVgFkh9v19l/CltBkRh2SqgUZYfCoELo7hUzLNh7cw2av8rcSUKSH3ra9MvpYfS -ANCnouzbgKix1gD6niT3pm1s5II3VuQ2vEcJunnoRFci9FzLXelTuL00MvuxERr7 -Fsqm1/D2JfKDbE09qy5bLWrWaTM6zOFQKN7F2edY2uaukLT6/w== -=Djed ------END PGP PUBLIC KEY BLOCK----- diff --git a/tests/automation/configuration/RPM-GPG-KEY-oracle-8 b/tests/automation/configuration/RPM-GPG-KEY-oracle-8 deleted file mode 100644 index d05afbd7..00000000 --- a/tests/automation/configuration/RPM-GPG-KEY-oracle-8 +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v2.0.14 (GNU/Linux) - -mQINBFyr9g0BEADVpB339zKe27a0LAQn4jWDYfX4ttCgYbX1sgyOKclO2ZMxdLIF -2Tz1KrmLim0am6ltTYIVpP0hVHsH1iy7MaVg1K/vaYIS8djL3SrmjX70P3QKIru5 -Hr8iGOKvX4jMHbUZmghZyVRdvl2QNc9oh+l+i3CzyChFlNV3dGlmsaBRT6o5Ecvn -ZQ8cVdsbFnRAYpCDO65wOCujWNVe2F5eA6xy4mQfVOCuF7jY1sb4zRanTVE0hZyy -ig6OeTZjutjr7V+kDrT5K3PdXn2kPsVWcEdJJOta+hqJ9wnA1aiTJNNpvRP6fJtv -iw8poJqJID7VUPTfGp38k6sPfe4BmqEfRSUbNT5JKCFvlp4Y39pHzmKfX+8jjeZ2 -XgBx/Z4GsW6q/tAOksZ8nHB/XIPZkr6V+tXXZP4D5peNIWLxhza585FDiGi8d1Z4 -KIMpeqJhUu24vre9rmYn2wOFP6GYZfi1KOMImAjQC13BktpAlSqDNzCQepoNfvoG -iO8v0sO8mHy16fpp+hk7T4hveScoYYIBaTMcdTElvPjA5mgXTaBF/qttF1LlFf51 -PvNkKQVoCR7V9+puZGsWeq9Kv+GaUYC3uKo96MKCO4G34uSu9uYo4eZ3yr7GslSM -6rB0Fi4yfDT9R9mS8YHpuCKhgQ5IUBl6x72h1s02+maheeH0CZMbV/7hEwARAQAB -tERPcmFjbGUgT1NTIGdyb3VwIChPcGVuIFNvdXJjZSBTb2Z0d2FyZSBncm91cCkg -PGJ1aWxkQG9zcy5vcmFjbGUuY29tPokCPgQTAQIAKAUCXKv2DQIbAwUJJZgGAAYL -CQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQglYuqa2YbaN53w/+Lx4cqKifslEa -BpWz4yqHcAtuz25sCW4wbH4V56EfKZAh+WQ/JwPFybSywqbzgIUrIlzg8CMuUnKM -5BElUkKPDYI+CjvUtP0B9eFThqjp7WNly0IQX8qC6p/gTLDXuEbKLj+EfLvKihqc -L2tJIaQWiQAaftG5DFHIanZpVr88eXJwAMCle/m29x7K4g0c959vZdFF7iggIcHl -TJ3GWGbLzRXi0fXVTQJAltR5Gx+FnRnSmAplL6j1UG1cgesZrfJZbNsl0+5Eq4oH -UN3sTgaqTYaMWR7jH6HFF+5d05ndpltLXbG6Ia1c1Z4e+ha2ehBnceBxSCt5VT5z -tmvJCm4QT4+S8AKsdQLpx3XWTWs5B41DYy3yQHaQz+So42YEtvGCemPsCfkid8ZN -Eltl9KM0iHYJbFehv2ckZe4RVNEDVgurlnEEKICvhfwS4bz2IQZPSYQLGLmUYwpp -kf2VjkDhTQUMp1iqLXsolCjDfTcZrlUaAEXP7A1wuLBlAEHE/yZOZbqcgE4AZKkV -nJYmu2lrSkNhisMOVsVhDyCyFEw1+fD+RnvR9uNHOqgeTV/6kOyGu+nC8dnwKyq0 -wLJzu+8ENdemcvld9pwx3FPWTGQ4GGNJ3MVdwfwnYkg5vKGDSOmPDuEnnxkaPJrT -JIHSJXfjSg/M0PiLGXcOMpGVNebpSQK5Ag0EXKv2DQEQAKHZmlvNo+/+amYh9Ogn -lzSUctqLENke8m7Q7HXUakEZgTfRU0an+9TmfoUCyHS11q3A0l+FoB/FBT45ByxU -df850oQd0PApqo5NxNpQCqYgOCOpTHT0SnRh9gQCDGgzfYSZl8ME+izEU5WOjQ51 -g/2ajODXGIWHPwYE8lZyF7tE7bFNEwve7sIrQefAR0eASz8PMFdQ5US/vYZQ+jeL -U2dZqfl2B7AnP7MuXpa31MkhB3laYdH+vWaQLPbk/bh7cvKtkDbDHY13NS2nTpWy -fjeUCFpDHupzMNkclc0If44WKA1a0sO7d6mBWyVM0IgrCxieXJ/EZVFkhXEulcGu -+L0iHhkR9NA6dRXvC/wJnsCASjzxFqyzlhTfNR1QwWdZJpC8Il9oH3VcrT4TtEvJ -DxuXTMqeMSOfNSsdqaiE9u6tgbC13qBTvbsoBg9Rs2hY2nRqUhNhvMoRbt1U1qXw -hn/9g1f+1i3GvED6j2AuWMnU9zehR32iuGQl48ko428bREPz08AY++v3/n4U/cbs -oJzAvCg1+WYQe26v0mIJIuzOmeFRmXcaTHUZvyY6aqSvQeOno0h1cjRZAN9T6Z8q -lYbwh8yhGNlfybQPmld/oeiDNVr43sSl6W02TOLFZ36h2eGpt2LKUVz+zFQwrAdF -u6Uo/1lgGRGbzBezNgUCkQCLABEBAAGJAiUEGAECAA8FAlyr9g0CGwwFCSWYBgAA -CgkQglYuqa2YbaO4Eg//WREjdHosvTLPbjDwmtH0R3Twis/eqHPSq57I9jDSOvRD -Wkv4/CidBu1+FsTDpInn4wiAIE9eMb/L89Cc2Y5LyzHlzORJMEgzEqcjIewqRcEy -vMbyTnx4Gc4hKiMhRcMLWQuWp6/JT09+B3oPzQLXHvuAuKu0ZjFJl16obdoL7tAT -AOPtqmxkwt22G1lBkGUVCOiEuwg1+9AgiMhDHt6Gg8wHjKoQiHv4peGDKxcldfTF -TAH03vx+2mwT61a/RjE1YqHzmlqmTa89SDNDStrG2VikSB0YdDuqSzB6FMcURktJ -wwyhOKEjJ4c20wZG5xQfiJfOcij2QYPW5vYtQNCnKfspsF7BCP/GXdYATgyajCxp -4pkNsAZlRyHUx1zPMR1E1+se+l5s18y0V+b+1YBEmAmcEML9Rev+Rbyd+YXmJ+P9 -rDThkvPXxV+4HZgl0mXvTd1CUUnNnd40ZSzFo8hTmr/+j2T7iR3wcxnoyv/d8MOU -quYsKDLdBr9ng+Cvbf/8lNJJ6dbCQAcEXvRn8FKjq+iP+hHPXXOh/FrMvBJrbD3V -6F65eyvyLMN74Caxd2B2ru01yLNGARZr8iOH3cdt4byC0lSA51yNePooe6HfgCEA -sFEvovilr7kFbspDGrP49wh0evtRDPmqfjMLiiaRxOXefOjbh8XqrfNGDTCQzdE= -=dTZ0 ------END PGP PUBLIC KEY BLOCK----- diff --git a/tests/automation/configuration/oci-utils-automation.repo-7 b/tests/automation/configuration/oci-utils-automation.repo-7 deleted file mode 100644 index d948ae28..00000000 --- a/tests/automation/configuration/oci-utils-automation.repo-7 +++ /dev/null @@ -1,6 +0,0 @@ -[oci-utils-automation] -name=Oracle Linux $releasever - $basearch - latest -baseurl=http://_IPIP_/yum/_UUUU_/OL7/$basearch/ -gpgcheck=1 -enabled=1 - diff --git a/tests/automation/configuration/oci-utils-automation.repo-8 b/tests/automation/configuration/oci-utils-automation.repo-8 deleted file mode 100644 index 2215d7f0..00000000 --- a/tests/automation/configuration/oci-utils-automation.repo-8 +++ /dev/null @@ -1,6 +0,0 @@ -[oci-utils-automation] -name=Oracle Linux $releasever - $basearch - latest -baseurl=http://_IPIP_/yum/_UUUU_/OL8/$basearch/ -gpgcheck=1 -enabled=1 - diff --git a/tests/automation/configuration/oci-utils-automation.spec b/tests/automation/configuration/oci-utils-automation.spec deleted file mode 100644 index 088ff5a6..00000000 --- a/tests/automation/configuration/oci-utils-automation.spec +++ /dev/null @@ -1,95 +0,0 @@ -Summary: oci-utils automation build and test utils -Name: oci-utils-automation -Version: 0.2.2 -Url: http://cloud.oracle.com/iaas -Release: 0%{?dist} -License: UPL -Group: Development/Tools -Source0: oci-utils-automation-%{version}.tar.gz -BuildArch: noarch - -BuildRoot: /tmp/oci-utils-automation - -%define is_el7 %(test "%{?dist}" = ".el7" && echo 1 || echo 0) -%define is_el8 %(test "%{?dist}" = ".el8" && echo 1 || echo 0) - -%define os_id /etc/redhat-release -# Default to ol7 -%if %is_el7 -%define os_version 7|7Server -%define os_tag 7 -%endif - -%if %is_el8 -%define os_version 8|8Server -%define os_tag 8 -%endif - -Requires: rpm -Requires: %{os_id} - -%description -This package contains utils for automation of oci-utils build and testing - -%prep -%setup -q - -%build - -%install -[ "${RPM_BUILD_ROOT}" != "/" ] && rm -rf "${RPM_BUILD_ROOT}" -mkdir -p "${RPM_BUILD_ROOT}/etc/yum.repos.d" -mkdir -p "${RPM_BUILD_ROOT}/usr/share/rhn" -# cp oci-utils-automation.repo-%{os_tag} ${RPM_BUILD_ROOT}/etc/yum.repos.d/oci-utils-automation.repo -cp %{getenv:HOME}/git_repo/tests/automation/configuration/oci-utils-automation.repo-%{os_tag} ${RPM_BUILD_ROOT}/etc/yum.repos.d/oci-utils-automation.repo -cp RPM-GPG-KEY-oracle-%{os_tag} ${RPM_BUILD_ROOT}/usr/share/rhn/RPM-GPG-KEY-oracle - -%clean -[ "${RPM_BUILD_ROOT}" != "/" ] && rm -rf "${RPM_BUILD_ROOT}" - -%files -%defattr(644, root, root) -/etc/yum.repos.d/oci-utils-automation.repo -/usr/share/rhn/RPM-GPG-KEY-oracle - -%pre -# Exit if this is a GIT machine -if [ -f /usr/local/git/etc/mkks-iso-version ] || [ -f /etc/OSCC-Release ] ; then - echo " - This is a GIT machine. This package is not for production machines. - - Aborting... - " - exit 1 -fi - -# Check OS release -egrep "%{os_version}" /etc/redhat-release > /dev/null 2>&1 -if [ $? -ne 0 ] ; then - echo " - Installed OS is not supported by this version of oci-utils-automation. - " - exit 1 -fi - -%post -# Backup and install config files -tstamp=`date -u +%Y-%m-%d-%H:%M` -[ -f /etc/sysconfig/rhn/sources ] && mv /etc/sysconfig/rhn/sources /etc/sysconfig/rhn/sources.uln-$tstamp -[ -f /etc/yum.repos.d/oci-utils-automation.repo ] && cp /etc/yum.repos.d/oci-utils-automation.repo /etc/yum.repos.d/oci-utils-automation.repo.uln-$tstamp -# cp /usr/share/rhn/RPM-GPG-KEY-oracle /usr/share/rhn/RPM-GPG-KEY-oracle -cp /usr/share/rhn/RPM-GPG-KEY-oracle /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle -rpm --import /usr/share/rhn/RPM-GPG-KEY-oracle - -%changelog -* Tue Nov 9 2021 Guido Tijskens ( 0.2.2-0) -- fixed os release check - -* Wed Sep 15 2021 Guido Tijskens ( 0.2.1-0) -- update structure - -* Wed Nov 18 2020 Guido Tijskens ( 0.1.1-1 ) -- user specific channels - -* Tue Nov 10 2020 Guido Tijskens ( 0.1.1-0 ) -- initial version diff --git a/tests/automation/create_lvm b/tests/automation/create_lvm deleted file mode 100644 index c5fe6219..00000000 --- a/tests/automation/create_lvm +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -x -# -# Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -# -# creates a volume of 51GB, creates a primary partition of 10GB, creates a logical volume with this partition as only -# physical device and creates a filesystem on this logical volume; a destroy script is also created. -# -NBPAR="${#}" -VALIDFS=(ext4 xfs) - -Usage() { - echo "Usage:" - echo " ${0} [ext4|xfs] (volume name)" -} -# command line -# file system type -if [ "${NBPAR}" -lt 1 ]; then - echo "Invalid filesystem type: ext4|xfs." - Usage - exit 1 -else - FSTYPE=${1} - if [[ ! " ${VALIDFS[*]} " =~ ${FSTYPE} ]]; then - echo "Invalid file system type." - Usage - fi -fi -# -# volume name -if [ ${NBPAR} -lt 2 ]; then - VOLNAME=gtijsken_lvm_vol01 -else - VOLNAME="${2}" -fi - -echo "${VOLNAME}" -# -oci-iscsi-config create --size 51 --volume-name "${VOLNAME}" --attach-volume -# -oci-iscsi-config show --details --no-truncate -# -VOL=$(oci-iscsi-config show --details --output-mode parsable |grep "${VOLNAME}") -echo "${VOL}" -# -IFS='#'; arrVOL=(${VOL}); unset IFS; -echo "${arrVOL}" -DEVICE="/dev/${arrVOL[6]}" -DISK="${arrVOL[6]}" -echo "${DISK}" -echo "${DEVICE}" -# -#fdisk "${DEVICE}" < "${destroy_script}" -echo "umount ${MOUNTPOINT}" >> "${destroy_script}" -IQN=$(oci-volume-data --key "${VOLNAME}" --par iqn --value-only) -OCID=$(oci-volume-data --key "${VOLNAME}" --par ocid --value-only) -# -# destroy lv -echo "lvchange --verbose -an ${MAPPERDEV}" >> "${destroy_script}" -echo "lvscan" >> "${destroy_script}" -echo "lvremove --yes --verbose ${LVDEV}" >> "${destroy_script}" -echo "lvscan" >> "${destroy_script}" -echo "vgremove --yes --verbose ${VOLGROUP}" >> "${destroy_script}" -echo "vgscan" >> "${destroy_script}" -echo "pvremove --yes --verbose ${PHYSICALVOL}" >> "${destroy_script}" -echo "lvscan" >> "${destroy_script}" -# -echo "oci-iscsi-config detach -I ${IQN}" >> "${destroy_script}" -echo "oci-iscsi-config destroy -O ${OCID} --yes" >> "${destroy_script}" -echo "df -h" >> "${destroy_script}" -echo "oci-iscsi-config show --details --no-truncate" >> "${destroy_script}" -echo "rmdir ${MOUNTPOINT}" >> "${destroy_script}" -chmod 755 "${destroy_script}" -echo "created ${destroy_script}" - diff --git a/tests/automation/create_user b/tests/automation/create_user deleted file mode 100755 index 0fa272b4..00000000 --- a/tests/automation/create_user +++ /dev/null @@ -1,216 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -# -# creates a user with given name and id, create the structure to run automated tests. -# -EXPECTEDNBPAR=5 -USERADD=$(command -v useradd) -GETENT=$(command -v getent) -PASSWD=$(command -v passwd) -SU=$(command -v su) -SED=$(command -v sed) -COPY=$(command -v cp) -CAT=$(command -v cat) -CHDIR="cd" -MKDIR=$(command -v mkdir) -DELETE="$(command -v rm) -rf" -CHMOD=$(command -v chmod) -CHOWN=$(command -v chown) -GROUPID=1000 -USERSHELL="/bin/bash" -BINDIR="bin" -TESTDIR="autotests" -CONFIGDIR="configuration" -GITDIR="git_repo" -WORKDIR="oci_operations/tests/automation/configuration" -# DIRLIST=( "${BINDIR}" "${TESTDIR}" "${CONFIGDIR}" "${GITDIR}") -DIRLIST=( "${BINDIR}" "${TESTDIR}" "${GITDIR}") -GITCLONE="cloneociutils" -TESTINSTANCE="oci_utils_test_instance" -CONFIGURETESTS="oci_utils_configure_tests" -ISCSIDATA="oci_utils_iscsi_data" -NETWORKDATA="oci_utils_network_data" -POOLDATA="oci_utils_pool_data" -BINLIST=( "${TESTINSTANCE}" "${CONFIGURETESTS}" "${ISCSIDATA}" "${NETWORKDATA}" "${POOLDATA}" ) -KEYFILENAME="oci_api_key.pem" -# -# todo: -# hardcode github link to automation. -GIT=$(command -v git) -# GITHUBURL="https://github.com/oracle/oci-utils.git" -GITHUBURL="https://github.com/guidotijskens/oci-utils.git" -# -# https proxy -HTTPSPROXY="http://www-proxy-hqdc.us.oracle.com:80" - -Usage() { - echo "" - echo "Usage:" - echo "" - echo "${0} " - echo "" - echo " : the name of the user to be created." - echo " : the userid for the user." - echo " : the sdk config file." - echo " : the sdk key file." - echo " : the branch to be used with test list and automation code." - echo "" - echo " Creates a user with name and userid " - echo " with groupid 1000 and in group wheel with home" - echo " directory /home/; configures the oci-sdk for direct authentication;" - echo " clones github oci-utils repository and checks out a branch." - echo "" -} - -MessageStd() { - local MSGNOW=$(date '+%d-%b-%Y %H:%M:%S') - echo "${MSGNOW} --- MSG --- ${1}" -} - -MessageErrBase() { - local MSGNOW=$(date '+%d-%b-%Y %H:%M:%S') - echo "${MSGNOW} --- ERR --- ${1}" -} - -MessageErrFatal() { - RETVAL="${1}" - MSG="${2}" - if [ "${RETVAL}" -ne 0 ]; then - MessageErrBase "${MSG}: ${RETVAL}" - exit 1 - fi -} - -ExitOnError() { - RETV="${1}" - ERRORMESSAGE="${2}" - SUCCESSMESSAGE="${3}" - MessageErrFatal "${RETV}" "${ERRORMESSAGE}" - MessageStd "${SUCCESSMESSAGE}" -} - -NBPAR="${#}" -if [ ${NBPAR} -ne ${EXPECTEDNBPAR} ]; then - MessageErrBase "username, userid, config, key file and/or branch missing" - Usage - exit 1 -fi - -USERNAME=${1} -USERID=${2} -SDKCONFIG=${3} -KEYFILE=${4} -GITBRANCH=${5} -MessageStd "Username is ${USERNAME}" -MessageStd "UserID is ${USERID}" -MessageStd "SDK config file is ${SDKCONFIG}" -MessageStd "Key file ${KEYFILE}" -MessageStd "git branch ${GITBRANCH}" -# -HOMEDIR="/home/${USERNAME}" -MessageStd "user home directory is ${HOMEDIR}" -HOMEBINDIR="${HOMEDIR}/bin" -MessageStd "user bin directory is ${HOMEBINDIR}" -HOMEOCI="${HOMEDIR}/.oci" -MessageStd ".oci is ${HOMEOCI}" -HOMEOCICONFIG="${HOMEOCI}/config" -MessageStd "config file is ${HOMEOCICONFIG}" -HOMESDKKEY="${HOMEOCI}/${KEYFILENAME}" -MessageStd "sdk key file is ${HOMESDKKEY}" -HOMEGITDIR=${HOMEDIR}/${GITDIR} -MessageStd "git repositroy directory is ${HOMEGITDIR}" -HOMEAUTOMATION=${HOMEGITDIR}/tests/automation -MessageStd "automation directory is ${HOMEAUTOMATION}" -MASTERMAKE=${HOMEAUTOMATION}/Makefile -MessageStd "Makefile location is ${MASTERMAKE}" -# -# -${GETENT} passwd "${USERNAME}" > /dev/null 2>&1 -RETVAL=${?} -if [ ${RETVAL} -eq 0 ]; then - MessageErrFatal "${USERNAME} already exists" -fi -# -# add user -${USERADD} -c "user ${USERNAME}" -d "${HOMEDIR}" -g ${GROUPID} -G wheel -m -s "${USERSHELL}" -u "${USERID}" "${USERNAME}" -ExitOnError "${?}" "Failed to create user ${USERNAME}" "${USERNAME} created successfully." -${PASSWD} "${USERNAME}" -ExitOnError "${?}" "Failed to set password for ${USERNAME}" "Password for ${USERNAME} set successfully." -# -# create automation directories -for thisdir in "${DIRLIST[@]}" -do - ${SU} -l "${USERNAME}" -c "${MKDIR} -p ${thisdir}" - ExitOnError ${?} "Failed to create ${thisdir}" "Created ${thisdir} successfully." -done -# -# create oci sdk config directory -${SU} -l "${USERNAME}" -c "${MKDIR} ${HOMEOCI}" -ExitOnError "${?}" "Failed to create ${HOMEOCI}" "${HOMEOCI} created successfully." -# -# chmode sdk config directory -${SU} -l "${USERNAME}" -c "${CHMOD} 700 ${HOMEOCI}" -ExitOnError "${?}" "Failed to ${CHMOD} 700 ${HOMEOCI}" "${HOMEOCI} permission set to 700 successfully." -# -# copy sdk config file -${SU} -l "${USERNAME}" -c "${COPY} ${SDKCONFIG} ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to ${COPY} ${SDKCONFIG} to ${HOMEOCICONFIG}" "Copied ${SDKCONFIG} to ${HOMEOCICONFIG} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMEOCICONFIG}" "${HOMEOCICONFIG} permissions set to 600 successfully." -# -# copy and update key file -${SU} -l "${USERNAME}" -c "${COPY} ${KEYFILE} ${HOMESDKKEY}" "Copied ${KEYFILE} to ${HOMESDKKEY} successfully." -ExitOnError "${?}" "Failed to ${COPY} ${KEYFILE} to ${HOMESDKKEY}" -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMESDKKEY}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMESDKKEY}" -RETVAL="${?}" -MessageErrFatal ${RETVAL} "Failed to ${CHMOD} 600 ${HOMESDKKEY}" "${SED} -i /key_file/c\"key_file=${HOMESDKKEY}\" ${HOMEOCICONFIG}" -${SU} -l "${USERNAME}" -c "${SED} -i /key_file/c\"key_file=${HOMESDKKEY}\" ${HOMEOCICONFIG}" -# -# clone git -#${SU} -l ${USERNAME} -c "https_proxy=${HTTPSPROXY} ${GIT} clone ${GITHUBURL} ${HOMEGITDIR}" -#ExitOnError ${?} "Failed to clone ${GITHUBURL} to ${HOMEGITDIR}" "${GITHUBURL} cloned to ${HOMEGITDIR} successfully." -# -# checkout branch -#${SU} -l ${USERNAME} -c "${CHDIR} ${HOMEGITDIR} && ${GIT} checkout ${GITBRANCH} && ${CHDIR} ~" -#ExitOnError ${?} "Failed to checkout ${GITBRANCH}" "Checkout ${GITBRANCH} successfully" -# -# create clone script to ${HOME}/bin -${CAT} << EOT > ${HOMEBINDIR}/${GITCLONE} -#!/bin/bash -[ "\$#" -ne 1 ] && echo "Usage: ${0} " && exit -THISGITBRANCH="\${1}" -${DELETE} ${HOMEGITDIR} -https_proxy=${HTTPSPROXY} ${GIT} clone ${GITHUBURL} ${HOMEGITDIR} -${CHDIR} ${HOMEGITDIR} -${GIT} checkout \${THISGITBRANCH} -THISBRANCH=\$(${GIT} symbolic-ref --short HEAD) -echo "\"Current branch \${THISBRANCH}\"" -EOT -ExitOnError "${?}" "Failed to create ${HOMEDIR}/bin/${GITCLONE}" "Created ${HOMEDIR}/bin/${GITCLONE}} successfully." -# -# chown ${GITCLONE} -${CHOWN} ${USERID}:${GROUPID} ${HOMEDIR}/bin/${GITCLONE} -ExitOnError "${?}" "Failed to change owmer of ${HOMEDIR}/bin/${GITCLONE}" "Changed owner of ${HOMEDIR}/bin/${GITCLONE} successfully." -# -# chmod 755 ${GITCLONE} -${SU} -l "${USERNAME}" -c "${CHMOD} 755 ${HOMEDIR}/bin/${GITCLONE}" -ExitOnError "${?}" "Failed to ${CHMOD} 755 ${HOMEDIR}/bin/${GITCLONE}" "${HOMEDIR}/bin/${GITCLONE} permission set to 755 successfully." - -# clone git -${SU} -l ${USERNAME} -c "${HOMEDIR}/bin/${GITCLONE} ${GITBRANCH}" -ExitOnError ${?} "Failed to clone ${GITHUBURL} to ${HOMEGITDIR}" "${GITHUBURL} cloned to ${HOMEGITDIR} successfully." -# -# copy Makefile -${SU} -l ${USERNAME} -c "${COPY} ${MASTERMAKE} ${HOMEDIR}" -ExitOnError ${?} "Failed to copy ${MASTERMAKE} to ${HOMEDIR}" "Copied ${MASTERMAKE} to ${HOMEDIR} successfully." -# -# populate bin -for thisbin in "${BINLIST[@]}" -do - ${SU} -l "${USERNAME}" -c "${COPY} ${HOMEAUTOMATION}/${thisbin}.py ${HOMEBINDIR}/${thisbin}" - ExitOnError "${?}" "Failed to ${COPY} ${thisbin}.py to ${HOMEBINDIR}/${thisbin}" "Copied ${thisbin}.py to ${HOMEBINDIR}/${thisbin} successfully." -done \ No newline at end of file diff --git a/tests/automation/create_volume b/tests/automation/create_volume deleted file mode 100644 index 7a5e33d4..00000000 --- a/tests/automation/create_volume +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash -x -# -# Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -# -# creates a volume of 51GB, creates a primary partition of 10GB and creates a filesystem on this partition; a destroy -# script is als created. -# -NBPAR="${#}" -VALIDFS=(ext4 xfs) - -Usage() { - echo "Usage:" - echo " ${0} [ext4|xfs] (volume name)" -} -# command line -# file system type -if [ "${NBPAR}" -lt 1 ]; then - echo "Invalid filesystem type: ext4|xfs." - Usage - exit 1 -else - FSTYPE=${1} - if [[ ! " ${VALIDFS[*]} " =~ ${FSTYPE} ]]; then - echo "Invalid file system type." - Usage - fi -fi -# -# volume name -if [ ${NBPAR} -lt 2 ]; then - VOLNAME=gtijsken_vol01 -else - VOLNAME="${2}" -fi - -echo "${VOLNAME}" -# -oci-iscsi-config create --size 51 --volume-name "${VOLNAME}" --attach-volume -# -oci-iscsi-config show --details --no-truncate -# -VOL=$(oci-iscsi-config show --details --output-mode parsable |grep "${VOLNAME}") -echo "${VOL}" -# -IFS='#'; arrVOL=(${VOL}); unset IFS; -echo "${arrVOL}" -DEVICE="/dev/${arrVOL[6]}" -echo "${DEVICE}" -# -fdisk "${DEVICE}" < "${destroy_script}" -echo "umount ${MOUNTPOINT}" >> "${destroy_script}" -IQN=$(oci-volume-data --key "${VOLNAME}" --par iqn --value-only) -OCID=$(oci-volume-data --key "${VOLNAME}" --par ocid --value-only) -echo "oci-iscsi-config detach -I ${IQN}" >> "${destroy_script}" -echo "oci-iscsi-config destroy -O ${OCID} --yes" >> "${destroy_script}" -echo "df -h" >> "${destroy_script}" -echo "oci-iscsi-config show --details --no-truncate" >> "${destroy_script}" -echo "rmdir ${MOUNTPOINT}" >> "${destroy_script}" -chmod 755 "${destroy_script}" -echo "created ${destroy_script}" diff --git a/tests/automation/data/LICENSE.txt b/tests/automation/data/LICENSE.txt deleted file mode 100644 index ca505d9b..00000000 --- a/tests/automation/data/LICENSE.txt +++ /dev/null @@ -1,6 +0,0 @@ -// oci-utils -// -// Copyright (c) 2019, 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http://oss.oracle.com/licenses/upl. - diff --git a/tests/automation/data/README.md b/tests/automation/data/README.md deleted file mode 100644 index 09630fb3..00000000 --- a/tests/automation/data/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# oci utils automated testing - -## base module for oci utils automated testing. - diff --git a/tests/automation/data/base_instance/data.tf b/tests/automation/data/base_instance/data.tf deleted file mode 100644 index d22f5595..00000000 --- a/tests/automation/data/base_instance/data.tf +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "http" "channel_rpm" { - url = "http://${var.server_ip}/channel_rpms/${var.os_user}/" -} \ No newline at end of file diff --git a/tests/automation/data/base_instance/main.tf b/tests/automation/data/base_instance/main.tf deleted file mode 100644 index 7ae9729d..00000000 --- a/tests/automation/data/base_instance/main.tf +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//FLEXvariable "instance_flex_memory_in_gbs" { -//FLEX description = "instance memorry size in GB." -//FLEX type = number -//FLEX} - -//FLEXvariable "instance_flex_ocpus" { -//FLEX description = "amount of instance ocpus." -//FLEX type = number -//FLEX} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "script_path" { - description = "path to bash script direcory" - type = string -} - -provider "oci" { - tenancy_ocid = var.tenancy_ocid - user_ocid = var.user_ocid - private_key_path = var.oci_private_key - fingerprint = var.fingerprint - region = var.region - // auth = var.auth -} - -resource "oci_core_instance" "test_instance" { - count = "1" - availability_domain = var.availability_domain - compartment_id = var.compartment_ocid - display_name = var.instance_display_name - shape = var.shape -//FLEX shape_config { -//FLEX memory_in_gbs = var.instance_flex_memory_in_gbs -//FLEX ocpus = var.instance_flex_ocpus -//FLEX } - create_vnic_details { - subnet_id = var.subnet_ocid - display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - } - - source_details { - source_type = var.source_type - source_id = var.source_ocid - } - - preserve_boot_volume = false - - metadata = { - ssh_authorized_keys = file(var.ssh_public_key) - } - - timeouts { - create = "60m" - } - -} - -// install repo. -resource "null_resource" "install_repo" { - depends_on = [oci_core_instance.test_instance] - provisioner "file" { - source = "/var/www/html/channel_rpms/${var.os_user}/" - destination = "/tmp/" - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.PUBIP_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - - provisioner "remote-exec" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.PUBIP_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - script = "${var.script_path}/install_oci_utils_automation.sh" - } - - provisioner "remote-exec" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.PUBIP_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /logs", - "/bin/sudo --preserve-env chmod 777 /logs" - ] - } -} - diff --git a/tests/automation/data/base_instance/output.tf b/tests/automation/data/base_instance/output.tf deleted file mode 100644 index 1898a6f1..00000000 --- a/tests/automation/data/base_instance/output.tf +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - value = oci_core_instance.test_instance.*.private_ip[0] -} - -//PUBIPoutput "instance_public_ip" { -//PUBIP description = "Public IPs of created instance." -//PUBIP value = oci_core_instance.test_instance.*.public_ip[0] -//PUBIP} - -output "boot_volume_ocid" { - value = oci_core_instance.test_instance.*.boot_volume_id[0] -} - -output "instance_ocid" { - value = oci_core_instance.test_instance.*.id[0] -} - diff --git a/tests/automation/data/scripts/install_oci_utils_automation.sh b/tests/automation/data/scripts/install_oci_utils_automation.sh deleted file mode 100644 index 8686c04c..00000000 --- a/tests/automation/data/scripts/install_oci_utils_automation.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http:/oss.oracle.com/licenses/upl. - -RPM=$(command -v rpm) -GREP=$(command -v grep) -FIND=$(command -v find) -SED=$(command -v sed) -MKDIR=$(command -v mkdir) -DNF=dnf -SYSTEMCTL=$(command -v systemctl) -SUDO=$(command -v sudo) -OSVERSION=$(${SED} -rn 's/.*([0-9])\.[0-9].*/\1/p' /etc/redhat-release) -if ! command -v dnf; then -installrpm=$(command -v yum) -${SUDO} --login ${installrpm}-config-manager --enablerepo ol${OSVERSION}_developer -else -installrpm=$(command -v dnf) -${SUDO} --login ${installrpm} config-manager --set-enabled ol${OSVERSION}_developer -fi -${SUDO} --login ${installrpm} clean all -${SUDO} --login ${installrpm} repolist - -${SUDO} --login ${MKDIR} -p /root/test_data/test_rpms -${SUDO} --login ${MKDIR} -p /root/test_data/install_rpms - -${SUDO} --login ${installrpm} --assumeyes erase oci-utils -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-kvm -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-migrate -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-outest -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-oumtest -# -# excluding the kernel can cause the update failing -# ${SUDO} --login ${installrpm} --assumeyes update --exclude=kernel*,oci-utils* -${SUDO} --login ${installrpm} --assumeyes install tree strace tmux - -el=el$(rpm -q --queryformat '%{RELEASE}' rpm | grep -o [[:digit:]]*\$) -${SUDO} --login "${FIND}" /tmp -name "oci-utils*el${OSVERSION}*rpm" -exec ${installrpm} -y localinstall {} \; -# -# install packages to be tested -${SUDO} --login ${installrpm} repository-packages oci-utils-automation install --assumeyes --nogpgcheck - -${SUDO} --login ${SYSTEMCTL} enable ocid -${SUDO} --login ${SYSTEMCTL} start ocid diff --git a/tests/automation/data/scripts/install_oci_utils_kvm_automation.sh b/tests/automation/data/scripts/install_oci_utils_kvm_automation.sh deleted file mode 100644 index dc250f5c..00000000 --- a/tests/automation/data/scripts/install_oci_utils_kvm_automation.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http:/oss.oracle.com/licenses/upl. - -RPM=$(command -v rpm) -GREP=$(command -v grep) -FIND=$(command -v find) -SED=$(command -v sed) -MKDIR=$(command -v mkdir) -DNF=dnf -SYSTEMCTL=$(command -v systemctl) -SUDO=$(command -v sudo) -OSVERSION=$(${SED} -rn 's/.*([0-9])\.[0-9].*/\1/p' /etc/redhat-release) -if ! command -v dnf; then -installrpm=$(command -v yum) -${SUDO} --login ${installrpm}-config-manager --enablerepo ol${OSVERSION}_developer -else -installrpm=$(command -v dnf) -${SUDO} --login ${installrpm} config-manager --set-enabled ol${OSVERSION}_developer -fi - -${SUDO} --login ${MKDIR} -p /root/test_data/test_rpms -${SUDO} --login ${MKDIR} -p /root/test_data/install_rpms - -${SUDO} --login ${installrpm} --assumeyes erase oci-utils -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-kvm -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-migrate -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-outest -${SUDO} --login ${installrpm} --assumeyes erase oci-utils-oumtest -# -# excluding the kernel can cause the update failing -# ${SUDO} --login ${installrpm} --assumeyes update --exclude=kernel*,oci-utils* -${SUDO} --login ${installrpm} --assumeyes install tree strace tmux - -el=el$(rpm -q --queryformat '%{RELEASE}' rpm | grep -o [[:digit:]]*\$) -${SUDO} --login "${FIND}" /tmp -name "oci-utils*el${OSVERSION}*rpm" -exec ${installrpm} -y localinstall {} \; - -${SUDO} --login ${installrpm} clean all -${SUDO} --login ${installrpm} repolist -${SUDO} --login ${installrpm} repository-packages oci-utils-automation install --assumeyes --nogpgcheck - -${SUDO} --login ${SYSTEMCTL} enable ocid -${SUDO} --login ${SYSTEMCTL} start ocid - -# -# kvm specific -${SUDO} --login ${MKDIR} -p /isos diff --git a/tests/automation/data/test_iscsi/data.tf b/tests/automation/data/test_iscsi/data.tf deleted file mode 100644 index 8130d272..00000000 --- a/tests/automation/data/test_iscsi/data.tf +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} - diff --git a/tests/automation/data/test_iscsi/main.tf b/tests/automation/data/test_iscsi/main.tf deleted file mode 100644 index 34644e3f..00000000 --- a/tests/automation/data/test_iscsi/main.tf +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape - source_ocid = var.source_ocid - source_type = var.source_type - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path -} - -resource "null_resource" "run_test_cli_iscsi_config" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_cli_iscsi_config > /logs/run_test_cli_iscsi_config 2>&1" - ] - } -} - -resource "null_resource" "run_test_iscsiadm" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_iscsiadm > /logs/run_test_iscsiadm 2>&1" - ] - } -} diff --git a/tests/automation/data/test_iscsi/terraform_version.tf b/tests/automation/data/test_iscsi/terraform_version.tf deleted file mode 100644 index d0fcb2b9..00000000 --- a/tests/automation/data/test_iscsi/terraform_version.tf +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} - diff --git a/tests/automation/data/test_metadata/data.tf b/tests/automation/data/test_metadata/data.tf deleted file mode 100644 index 358b8db2..00000000 --- a/tests/automation/data/test_metadata/data.tf +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} - diff --git a/tests/automation/data/test_metadata/main.tf b/tests/automation/data/test_metadata/main.tf deleted file mode 100644 index 621a165e..00000000 --- a/tests/automation/data/test_metadata/main.tf +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape - source_ocid = var.source_ocid - source_type = var.source_type - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path -} - -resource "null_resource" "run_test_oci_metadata" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo mkdir /logs && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_oci_metadata > /logs/run_test_oci_metadata 2>&1" - ] - } -} - -resource "null_resource" "run_test_cli_metadata" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo mkdir /logs && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_cli_metadata > /logs/run_test_cli_metadata 2>&1" - ] - } -} diff --git a/tests/automation/data/test_metadata/terraform_version.tf b/tests/automation/data/test_metadata/terraform_version.tf deleted file mode 100644 index 12617d4e..00000000 --- a/tests/automation/data/test_metadata/terraform_version.tf +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} - diff --git a/tests/automation/data/test_various/data.tf b/tests/automation/data/test_various/data.tf deleted file mode 100644 index 8130d272..00000000 --- a/tests/automation/data/test_various/data.tf +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} - diff --git a/tests/automation/data/test_various/main.tf b/tests/automation/data/test_various/main.tf deleted file mode 100644 index 36f6c149..00000000 --- a/tests/automation/data/test_various/main.tf +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape - source_ocid = var.source_ocid - source_type = var.source_type - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path -} - -resource "null_resource" "run_test_auth_helper" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_auth_helper > /logs/run_test_auth_helper 2>&1" - ] - } -} - -resource "null_resource" "run_test_cache" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_cache > /logs/run_test_cache 2>&1" - ] - } -} - -resource "null_resource" "run_test_exec_helpers" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_exec_helpers > /logs/run_test_exec-helper 2>&1 " - ] - } -} - -resource "null_resource" "run_test_exec_utils_config_helper" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_exec_utils-config-helper > /logs/run_test_exec_utils_config_helper 2>&1" - ] - } -} - -resource "null_resource" "run_test_network_helpers" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_network_helpers > /logs/run_test_network_helpers 2>&1" - ] - } -} - -resource "null_resource" "run_test_platform_helpers" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_platform_helpers > /logs/run_test_platform_helpers 2>&1 " - ] - } -} - -resource "null_resource" "run_test_row_printer" { - depends_on = [ - module.base_instance] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests --tests-base=/opt/oci-utils/tests/data --test-suite=tests.test_row_printer > /logs/run_test_row_printer 2>&1" - ] - } -} diff --git a/tests/automation/data/test_various/terraform_version.tf b/tests/automation/data/test_various/terraform_version.tf deleted file mode 100644 index d0fcb2b9..00000000 --- a/tests/automation/data/test_various/terraform_version.tf +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} - diff --git a/tests/automation/data/userdata/tests-env b/tests/automation/data/userdata/tests-env deleted file mode 100644 index a49b3afd..00000000 --- a/tests/automation/data/userdata/tests-env +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - - -# This file contains environement variables and script commands -# to be push on remote instance within /etc/profile.d - -export http_proxy=${http_proxy_url} -export https_proxy=${https_proxy_url} -export no_proxy=169.254.169.254,.oraclecloud.com,.oraclecorp.com,.us.oracle.com \ No newline at end of file diff --git a/tests/automation/data/userdata/tests-resolve b/tests/automation/data/userdata/tests-resolve deleted file mode 100644 index ca4ba550..00000000 --- a/tests/automation/data/userdata/tests-resolve +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -export search ${dns_search_domains} -export nameserver ${dns_server_ip} \ No newline at end of file diff --git a/tests/automation/oci_utils_configure_tests.py b/tests/automation/oci_utils_configure_tests.py deleted file mode 100755 index be06f154..00000000 --- a/tests/automation/oci_utils_configure_tests.py +++ /dev/null @@ -1,1195 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -"""Build the tf file for running one, multiple or all tests. -""" -import argparse -import errno -import getpass -import inspect -import json -import logging -import os -import shutil -import sys -import re -import tty -import termios -from datetime import datetime -from subprocess import call - -# -# locale -lc_all = 'en_US.UTF8' - -software_tree = 'git_repo' -logdir = 'logs' -autotestdir = 'autotests' -tfvars_file = 'instance_variables.tfvars.json' -default_log = 'test_config.log' -config_log = '' - -inline_code = "cd /opt/oci-utils/ && /bin/sudo --preserve-env /bin/python3 /opt/oci-utils/setup.py oci_tests " \ - "--tests-base=/opt/oci-utils/tests/data --test-suite=tests.{} > /logs/run_{}.log 2>&1" - -_logger = logging.getLogger(__name__) - - -def print_g(msg, term=True, destination=None): - """ - Write msg to stdout and to file. - - Parameters - ---------- - msg: str - The text. - term: bool - If true, write to stdout. - destination: str - Path of destination file. - - Returns - ------- - No return value. - """ - if term: - print('%s' % msg) - if not bool(destination): - destination = config_log - with open(destination, 'a') as f: - f.write('%s\n' % msg) - f.flush() - - -def print_g40(head, msg, term=True, destination=None): - """ - Write a message %40s: msg to stdout and file. - - Parameters - ---------- - head: str - The head. - msg: str - The text. - term: bool - If true, write to stdout. - destination: str - Path of destination file. - - Returns - ------- - No return value. - """ - print_g('%40s: %s' % (head, msg), term, destination) - - -def parse_args(): - """ - Parse the command line arguments. - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(description='Configure oci utils auto tests.') - parser.add_argument('-n', '--name', - action='store', - dest='test_name', - default=None, - help="The name of the test suite.") - parser.add_argument('-i', '--instance', - action='store', - dest='instance_display_name', - default=None, - help='The test instance.') - parser.add_argument('-d', '--data-directory', - action='store', - dest='datadir', - default='_DDDD_', - help='Root directory with data for auto test run, default is ~//data.') - parser.add_argument('-f', '--var-file', - action='store', - dest='varfilename', - default=tfvars_file, - help='filename to store the variables; the extension .tfvars.json is added automatically.') - parser._optionals.title = 'Arguments' - args = parser.parse_args() - return args - - -def _clear(): - """ - Clear screen. - - Returns - ------- - bool: True - """ - _ = call('clear' if os.name == 'posix' else 'cls') - return True - - -def _is_int(string_data): - """ - Verifies if string is a valid int. - - Parameters - ---------- - string_data: str - The string to be evaluated. - - Returns - ------- - bool: True on success, false otherwise. - """ - return re.match(r"[-+]?\d+$", string_data) is not None - - -def _get_current_user(): - """ - Get the current username. - - Returns - ------- - str: the username. - """ - return getpass.getuser() - - -def _get_current_user_home(): - """ - Get the home directory of the current user. - - Returns - ------- - str: the full path of the home directory. - """ - return os.path.expanduser('~') - - -def _from_stdin(prompt, default=None): - """ - Read from stdin, if default is not set to None, some input is expected. - - Parameters - ---------- - prompt: str - The stdin prompt. - default: - Default value. - - Returns - ------- - value read - """ - while True: - return_val = input('%-40s: ' % prompt) - if bool(return_val): - return return_val - else: - if default is not None: - return default - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def initialise_log(base_dir, *args): - """ - Initialise the logfile. - - Parameters - ---------- - base_dir: str - Path of the log directory. - args: tuple - Log file path base. - - Returns - ------- - str: full path of the log file. - """ - now = datetime.now() - log_path = base_dir - for dirfrag in list(args): - log_path = os.path.join(log_path, dirfrag) - os.makedirs(log_path, exist_ok=True) - global config_log - config_log = os.path.join(log_path, default_log + '_' + now.strftime('%Y%m%d%H%M')) - with open(config_log, 'w') as f: - f.write('') - f.flush() - return config_log - - -def _select_from(some_list, prompt, default_val=0): - """ - Select an item from a list. - - Parameters - ---------- - some_list: list - list of items. - prompt: str - prompt - default_val: int - default index value if no input. - - Returns - ------- - The list element. - """ - while 1 == 1: - selected_nb = input("%s ==> " % prompt) - if not bool(selected_nb): - selected_nb = str(default_val) - if _is_int(selected_nb): - select_index = int(selected_nb) - if 0 <= select_index < len(some_list): - break - print_g('Index %d out of range.' % select_index) - else: - print_g('Invalid input: %s' % selected_nb) - return some_list[select_index] - - -def _create_dir(dirname, backup=False): - """ - Create a directory, make a backup copy if already exists. - - Parameters - ---------- - dirname: str - Full path - backup: bool - If True, make a backup if already exists. - Returns - ------- - bool: True on success, false otherwise. - """ - try: - if backup: - if os.path.exists(dirname): - bck_name = dirname + '_%s' % datetime.now().strftime('%Y%m%d_%H%M') - os.rename(dirname, bck_name) - print_g('Renamed %s to %s' % (dirname, bck_name), term=False) - os.makedirs(dirname) - _logger.debug('Created %s', dirname) - except OSError as e: - if e.errno != errno.EEXIST: - print_g('Failed to create %s' % dirname, term=False) - return False - _logger.warning('%s already exists, might cause problems.', dirname) - return True - - -def _get_display_name(): - """ - Read instance display name from stdin. - - Returns - ------- - str: the display name. - """ - return _from_stdin('Instance Display Name: ') - - -def _get_test_name(): - """ - Read instance display name from stdin. - - Returns - ------- - str: the display name. - """ - return _from_stdin('Test Suite Name: ') - - -def _test_instance_defined(instance_name, root_dir): - """ - Verify if instance_name is defined. - - Parameters - ---------- - instance_name: str - name of instance to test. - root_dir: str - user home directory - - Returns - ------- - bool: True on success, False otherwise. - """ - return os.path.isdir(os.path.join(root_dir, autotestdir, instance_name)) - - -def _test_softwaretree_defined(root_dir): - """ - Verify if software_tree is defined. - - Parameters - ---------- - root_dir: str - user home directory - - Returns - ------- - bool: True on success, False otherwise. - """ - return os.path.isdir(os.path.join(root_dir, software_tree)) - - -def get_test_list(location): - """ - Get the list of available tests in directory location. - - Parameters - ---------- - location: str - (relative) path of the directory containing the tests. - - Returns - ------- - list: of tests. - """ - test_list = list() - if os.path.exists(location): - if os.path.isdir(location): - for fn in os.listdir(location): - if fn.startswith('test_'): - test_list.append(os.path.splitext(fn)[0]) - return test_list - - -def compose_tests(testlist): - """ - Compose a list of tests to execute. - - Parameters - ---------- - testlist: list - List of available tests. - - Returns - ------- - list: list of tests to execute. - """ - list_of_tests = list() - if not bool(testlist): - print_g('No tests found') - return None - testlist_s = ['quit'] - testlist_s.extend(testlist) - for tst in testlist_s: - print_g('%4d %-30s' % (testlist_s.index(tst), tst)) - while 1 == 1: - this_test = _select_from(testlist_s, 'Select test ( or 0 to quit).') - if this_test == 'quit': - return list_of_tests - list_of_tests.append(this_test) - - -def initialise_test(test_base, template_dir): - """ - initialise test. - - Parameters - ---------- - test_base: str - Directory where test to be created. - template_dir: str - Directory with the templates. - - Returns - ------- - bool: True on success, False otherwise - """ - try: - # - # create dir - os.makedirs(test_base, exist_ok=True) - # - # copy version - shutil.copy(os.path.join(template_dir, 'tf_version'), os.path.join(test_base, 'terraform_version.tf')) - # - # copy data - shutil.copy(os.path.join(template_dir, 'tf_data'), os.path.join(test_base, 'data.tf')) - # - # copy main heading - shutil.copy(os.path.join(template_dir, 'tf_main'), os.path.join(test_base, 'main.tf')) - # - # copy output - shutil.copy(os.path.join(template_dir, 'tf_output'), os.path.join(test_base, 'output.tf')) - return True - except Exception as e: - print_g('%s' % str(e)) - return False - - -def copy_base_scripts(data): - """ - Copy base instance to test env. - - Parameters - ---------- - data: dict - The configuration data - - Returns - ------- - bool: True on success, False otherwise. - """ - base_scripts = ['main.tf', 'data.tf', 'output.tf'] - try: - # - # create dir - os.makedirs(data['base_instance_dir'], exist_ok=True) - # - # copy scripts - for scr in base_scripts: - shutil.copy(os.path.join(data['base_instance_location'], scr), os.path.join(data['base_instance_dir'], scr)) - return True - except Exception as e: - print_g('%s' % str(e)) - return False - - -def create_test(test_base, template_dir, name, test_codeline, authentication): - """ - Add the specific test. - - Parameters - ---------- - test_base: str - Directory where test to be created. - template_dir: str - Directory with the templates. - name: str - Name of the test. - test_codeline: str - The unittest code line. - authentication: str - ip or apikey - - Returns - ------- - bool: True on success, False otherwise. - """ - main_f = os.path.join(test_base, 'main.tf') - print_g40('main tf', main_f) - test_f = os.path.join(template_dir, 'tf_test') - print_g40('test tf', test_f) - try: - main_fd = open(main_f, "a") - with open(test_f, "r") as test_fd: - main_fd.write(os.linesep) - for test_line in test_fd: - if authentication == 'apikey': - res_line = test_line.replace('_TTTT_', name).replace('_SSSS_', test_codeline).replace('_BBBB_', 'null_resource.oci_sdk_config') - else: - res_line = test_line.replace('_TTTT_', name).replace('_SSSS_', test_codeline).replace('_BBBB_', 'module.base_instance') - if not res_line.startswith('//'): - main_fd.write(res_line) - # print_g(res_line) - return True - except Exception as e: - print_g('Failed to create test %s: %s' % (name, str(e))) - return False - finally: - main_fd.close() - - -def add_apikey(test_base, template_dir): - """ - Add the oci-sdk config. - - Parameters - ---------- - test_base: str - Directory where test to be created. - template_dir: str - Directory with the templates. - - Returns - ------- - bool: True on success, False otherwise - """ - main_f = os.path.join(test_base, 'main.tf') - # print_g40('main tf', main_f) - apikey_f = os.path.join(template_dir, 'tf_apikey') - # print_g40('apikey tf', apikey_f) - try: - main_fd = open(main_f, "a") - with open(apikey_f, "r") as apikey_fd: - main_fd.write(os.linesep) - for apikey_line in apikey_fd: - if not apikey_line.startswith('//'): - main_fd.write(apikey_line) - # print_g(res_line) - return True - except Exception as e: - print_g('Failed to add apikey: %s' % str(e)) - return False - finally: - main_fd.close() - - -def init_struct(test_name, instance_name): - """ - Initialise config struct. - - Parameters - ---------- - test_name: str - The test suite name - instance_name: str - The instance display name. - - Returns - ------- - dict: the config structure. - """ - # - # exec dir - data = dict() - exec_dir = inspect.getfile(inspect.currentframe()) - data['instance_display_name'] = instance_name - print_g40('Instance', data['instance_display_name']) - data['test_name'] = test_name - print_g40('Test', data['test_name']) - data['exec_dir'] = os.path.dirname(exec_dir) - print_g40('Bin Directory', data['exec_dir']) - return data - - -def get_user_data(data): - """ - Collect operator data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - data['operator'] = _get_current_user() - data['operator_home'] = _get_current_user_home() - return data - - -def get_test_env(data): - """ - Define the directories involved. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - # - # software tree root - data['test_base'] = os.path.join(data['operator_home'], software_tree) - print_g40('Software Tree', data['test_base']) - # - # tests root - data['test_location'] = os.path.join(data['test_base'], 'tests') - print_g40('Tests Source Location', data['test_location']) - # - # terraform template root - data['template_dir'] = os.path.join(data['test_base'], 'tests', 'automation', 'templates') - print_g40('Template Location', data['template_dir']) - # - # base instance destination - data['base_instance_location'] = os.path.join(data['test_base'], 'tests', 'automation', 'data', 'base_instance') - print_g40('Base_Instance Location', data['base_instance_location']) - # - # test instance root - data['test_instance_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name']) - print_g40('Tests Instance Location', data['test_instance_dir']) - # - # test root - data['test_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], data['test_name']) - print_g40('Tests Location', data['test_dir']) - # - # base instance destination - data['base_instance_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'base_instance') - print_g40('Base_Instance', data['base_instance_dir']) - # - # scritps destination - data['script_path'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'sh_scripts') - print_g40('Scripts Location', data['script_path']) - # - # data - instance variables destination - data['data_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'data') - data['tfvarsfile'] = os.path.join(data['data_dir'], tfvars_file) - # - # data - instance test variables destination - data['data_test_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'data') - data['test_tfvarsfile'] = os.path.join(data['data_test_dir'], data['test_name'] + '_' + tfvars_file) - print_g40('Test parameter file', data['test_tfvarsfile']) - return data - - -def create_directories(data, args): - """ - Create directories for scripts. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - instance_display_name = data['instance_display_name'] - - if args.datadir != '_DDDD_': - data['data_dir'] = args.datadir + '/data' - print_g40('Data Location', data['data_dir']) - print_g40('Instance Variables', data['tfvarsfile']) - if not _create_dir(data['test_instance_dir']): - sys.exit(1) - if not _create_dir(data['script_path']): - sys.exit(1) - if not _create_dir(data['data_dir']): - sys.exit(1) - if not _create_dir(data['data_test_dir']): - sys.exit(1) - if not _create_dir(data['base_instance_dir']): - sys.exit(1) - if not _create_dir(data['test_dir']): - sys.exit(1) - return data - - -def copy_tfvars(data): - """ - Copy the variables file to the test environment. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - bool: True on success, False otherwise. - """ - try: - shutil.copy(data['tfvarsfile'], data['test_tfvarsfile']) - return True - except Exception as e: - print_g('%s' % str(e)) - return False - - -def is_flex_shape(data): - """ - Verify if the instance is to be build from a flex shape. - - Parameters - ---------- - data: dict - The config data. - - Returns - ------- - bool: True if flex shape, False if not - """ - # - # verify tfvars file for flex parameters - try: - with open(data['test_tfvarsfile'], 'rb') as tfvj: - tfvars_data = json.load(tfvj) - if 'instance_flex_memory_in_gbs' in tfvars_data and 'instance_flex_ocpus' in tfvars_data: - # - # is a flex shape - return True - else: - # - # is not a flex shape - return False - except Exception as e: - print_g('Failed to read %s' % data['tfvarsfile']) - raise 'tfvars file missing' - - -def is_public_ip(data): - """ - Verify if a public ip is to be assigned. - Parameters - ---------- - data: dict - The config data. - - Returns - ------- - bool: True if public ip, False otherwise - """ - # - # verify tfvars file for public parameters - try: - with open(data['test_tfvarsfile'], 'rb') as tfvj: - tfvars_data = json.load(tfvj) - if 'assign_public_ip' in tfvars_data: - if tfvars_data['assign_public_ip']: - return True - return False - except Exception as e: - print_g('Failed to read %s' % data['tfvarsfile']) - raise 'tfvars file missing' - - -def update_public_ip(data, public_ip): - """ - Update the script for public or private ip. - - Parameters - ---------- - data: dict - The configuration data. - public_ip: bool - If True set for public ip. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['template_dir'] - api_key = tf_scripts_dir + '/tf_apikey' - output_b = base_instance_dir + '/output.tf' - output_t = tf_scripts_dir + '/tf_output' - main_b = base_instance_dir + '/main.tf' - iptype = 'public' if public_ip else 'private' - print_g('operator home %s' % operator_home, term=False) - print_g('base instance dir %s' % base_instance_dir, term=False) - print_g('api key %s' % api_key, term=False) - print_g('output b %s' % output_b, term=False) - print_g('main b %s' % main_b, term=False) - print_g('iptype %s' % iptype, term=False) - - # - # tf_scripts/api_key - with open(api_key, 'r+') as fx: - api_text = fx.read() - api_text = re.sub('PUBIP', iptype, api_text) - fx.seek(0) - fx.write(api_text) - print_g('api text: %s' % api_text, term=False) - fx.truncate() - # - # base_instance/main - with open(main_b, 'r+') as fx: - main_text = fx.read() - main_text = re.sub('PUBIP', iptype, main_text) - fx.seek(0) - fx.write(main_text) - print_g('main text: %s' % main_text, term=False) - fx.truncate() - # - # output public ip if one available - if public_ip: - # - # base_instance/output - with open(output_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//PUBIP', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # tf_scripts/output - with open(output_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//PUBIP', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def update_for_flex(data): - """ - Update the terraform scripts for usage with Flex shapes. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - bool: True - """ - # - # tf_scripts/main.tf - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['template_dir'] - main_t = tf_scripts_dir + '/tf_main' - main_b = base_instance_dir + '/main.tf' - with open(main_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//FLEX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # base_instance/main.tf - with open(main_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//FLEX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def write_bash(fn, cmd): - """ - Write a command to the script file fn. - - Parameters - ---------- - fn: str - Full path of the script file. - cmd: str - The string. - - Returns - ------- - bool: True or False - """ - try: - if not os.path.exists(fn): - with open(fn, 'w') as fd: - fd.write('#!/bin/bash\n') - fd.flush() - os.chmod(fn, 0o755) - with open(fn, 'a') as fd: - fd.write('%s\n' % cmd) - fd.flush() - fd.write('RETVAL=${?}\n') - fd.flush() - fd.write('if [ $RETVAL -ne 0 ]; then\n') - fd.flush() - fd.write(' echo "%s failed"\n' % cmd) - fd.flush() - fd.write(' exit $RETVAL\n') - fd.flush() - fd.write(' echo "%s succeeded"\n' % cmd) - fd.write('fi\n') - fd.flush() - return True - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - return False - - -def init_file(fn): - """ - Initialise a flat file, i.e. erase and recreate if already exists. - - Parameters - ---------- - fn: str - The full path of the file. - - Returns - ------- - bool: True on success, False otherwise. - """ - try: - with open(fn, 'w') as f: - pass - except Exception as e: - print_g('%s' % str(e)) - return False - return True - - -def write_scripts(data): - """ - Write the scripts. - Parameters - ---------- - data: the configuration data. - - Returns - ------- - No return value. - """ - def_log_dir = data['operator_home'] - print_g('Run\n' - 'terraform -chdir=%s init\n' - 'terraform -chdir=%s validate\n' - 'terraform -chdir=%s plan -var-file=%s\n' - 'terraform -chdir=%s apply -var-file=%s -auto-approve | tee %s/creation.log\n' - 'terraform -chdir=%s destroy -var-file=%s -auto-approve' - % (data['test_dir'], - data['test_dir'], - data['test_dir'], data['test_tfvarsfile'], - data['test_dir'], data['test_tfvarsfile'], def_log_dir, - data['test_dir'], data['test_tfvarsfile'])) - create_script = data['operator_home'] \ - + '/' \ - + autotestdir \ - + '/%s_%s_create' % (data['instance_display_name'], data['test_name']) - if not init_file(create_script): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s init' - % data['test_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s validate' - % data['test_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s plan --var-file=%s' - % (data['test_dir'], data['test_tfvarsfile'])): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s apply --var-file=%s -auto-approve | tee %s/creation.log' - % (data['test_dir'], data['test_tfvarsfile'], def_log_dir)): - sys.exit(1) - try: - os.chmod(create_script, 0o755) - except Exception as e: - print_g('Failed to chmod 755 %s: %s' % (create_script, str(e))) - # - destroy_script = data['operator_home'] \ - + '/'\ - + autotestdir\ - + '/%s_%s_destroy' % (data['instance_display_name'], data['test_name']) - if not init_file(destroy_script): - sys.exit(1) - if not write_bash(destroy_script, 'terraform -chdir=%s destroy --var-file=%s -auto-approve | tee %s/destruction.log' - % (data['test_dir'], data['test_tfvarsfile'], def_log_dir)): - sys.exit(1) - try: - os.chmod(destroy_script, 0o755) - except Exception as e: - print_g('Failed to chmod 755 %s: %s' % (destroy_script, str(e))) - print_g('\nor\n%s\n%s' % (create_script, destroy_script)) - - -def main(): - """ - Configure tests. - - Returns - ------- - int: 0 on success, raises exception on failure. - """ - # - # locale - os.environ['LC_ALL'] = "%s" % lc_all - # - # parse the commandline - args = parse_args() - # - # clear - _ = _clear() - # - # user data - current_user = _get_current_user() - current_user_home = _get_current_user_home() - # - # name for the test. - test_name = args.test_name if args.test_name is not None else _get_test_name() - # - # test instance - instance_display_name = args.instance_display_name if args.instance_display_name is not None else _get_display_name() - # - # create log directory - global config_log - config_log = initialise_log(current_user_home, logdir, test_name) - debug_log = initialise_log(current_user_home, logdir, test_name) - # - # user data - print_g40('Current User', current_user) - print_g40('Current User Home', current_user_home) - # - # initialise logging - logging.basicConfig(filename=debug_log, - level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s (%(module)s:%(lineno)s) - %(message)s') - # - # exec dir - config_data = init_struct(test_name, instance_display_name) - # - # current user - config_data = get_user_data(config_data) - # - # test instance definition should be present - if not _test_instance_defined(config_data['instance_display_name'], config_data['operator_home']): - sys.exit('Instance definition %s does not exist.' % config_data['instance_display_name']) - # - # check directory with unittests. - if not _test_softwaretree_defined(config_data['operator_home']): - sys.exit('Software tree %s not present.' % software_tree) - # - # test environment - config_data = get_test_env(config_data) - # - # create directories - config_data = create_directories(config_data, args) - # - # copy base scripts - if not copy_base_scripts(config_data): - print_g('Failed to copy base_instance scripts.') - return 1 - # - # copy tfvars file to test env - if not copy_tfvars(config_data): - print_g('Failed to copy tfvars file to test') - return 1 - # - # flex shape? - if is_flex_shape(config_data): - if update_for_flex(config_data): - print_g40('Flex shape', 'updated') - # - # update public ip - _ = update_public_ip(config_data, is_public_ip(config_data)) - # - # compose the list of unittest files. - test_list = get_test_list(config_data['test_location']) - # print_g40('Tests', ' ') - # t = 1 - # for tst in test_list: - # print_g40('%s' % t, tst) - # t += 1 - # - # select tests from the list. - list_of_tests = compose_tests(test_list) - print_g40('Tests', ' ') - t = 1 - for tst in list_of_tests: - print_g40('%s' % t, tst) - t += 1 - # - # need oci-sdk config? - authentication = 'ip' - auth_requirement = 'ip' - if not _read_yn('Instance Principal Auth'): - authentication = 'apikey' - auth_requirement = 'apikey' - if not add_apikey(config_data['test_dir'], config_data['template_dir']): - print_g('Failed to add api key code.') - sys.exit(1) - print_g40('Authentication', authentication) - # - if bool(list_of_tests): - # - # initialise test - it = initialise_test(config_data['test_dir'], config_data['template_dir']) - if it: - if authentication == 'apikey': - if not add_apikey(config_data['test_dir'], config_data['template_dir']): - sys.exit('Failed to add api_key config') - for tst in list_of_tests: - ct = create_test(config_data['test_dir'], config_data['template_dir'], tst, inline_code.format(tst, tst), authentication) - if not ct: - return 1 - if auth_requirement == 'apikey': - _ = (config_data['test_dir'], config_data['template_dir']) - else: - print_g('Failed to create test.') - return 1 - print_g('Created test %s' % test_name) - write_scripts(config_data) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/automation/oci_utils_iscsi_data.py b/tests/automation/oci_utils_iscsi_data.py deleted file mode 100755 index f61469bd..00000000 --- a/tests/automation/oci_utils_iscsi_data.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Find a the value af an attribute of an iscsi volume based on the value of an attribute of the volume. -""" -import argparse -import subprocess -import sys - -oci_iscsi_path = '/bin/oci-iscsi-config' -volume_attached_fields = ['iqn', - 'name', - 'ocid', - 'persistentportal', - 'currentportal', - 'state', - 'device', - 'size'] -volume_all_fields = ['name', - 'size', - 'attached', - 'ocid', - 'iqn', - 'compartment', - 'availabilitydomain'] - - -def parse_args(): - """ - Parse command line parameters. - - Returns - ------- - namespace parsed arguments. - """ - choicelist = list(set(volume_all_fields + volume_attached_fields)) - parser = argparse.ArgumentParser(description='Utility for collecting 1 attribute of 1 volume.') - parser.add_argument('-i', '--input_field', - action='store', - type=str, - required=True, - choices=choicelist, - help='The volume field to select the volume.') - parser.add_argument('-v', '--input-value', - action='store', - type=str, - required=True, - help='The value of the select field.') - parser.add_argument('-o', '--output-field', - choices=choicelist, - type=str, - required=True, - help='The field the value requested from.') - return parser - - -def get_volume_data(index, val, field): - """ - Return val for volume based on index. - - Parameters - ---------- - index: str - base field name. - val: str - base field value. - field: str - requested field value. - - Returns - ------- - str: the requested value, None if absent. - """ - cmd = [oci_iscsi_path, 'show', '--detail', '--no-truncate', '--output-mode', 'parsable', '--all'] - all_volume_data = subprocess.check_output(cmd).decode('utf-8').splitlines() - - for vol in all_volume_data: - vol_list = vol.split('#') - if vol_list[2].startswith('ocid1.'): - if index not in volume_attached_fields or field not in volume_attached_fields: - continue - # is a volume in the 'attached' list - if vol_list[volume_attached_fields.index(index)] == val: - return vol_list[volume_attached_fields.index(field)] - else: - if index not in volume_all_fields or field not in volume_all_fields: - continue - # is a volume in the 'all' list - if vol_list[volume_all_fields.index(index)] == val: - return vol_list[volume_all_fields.index(field)] - return None - - -def main(): - """ - main - - Returns - ------- - No retunr value. - """ - parser = parse_args() - args = parser.parse_args() - print(get_volume_data(args.input_field, args.input_value, args.output_field)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/automation/oci_utils_network_data.py b/tests/automation/oci_utils_network_data.py deleted file mode 100755 index 7e88dac6..00000000 --- a/tests/automation/oci_utils_network_data.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Find a the value af an attribute of a vnic based on the value of an attribute of the vnic. -""" -import argparse -import subprocess -import sys - -oci_network_path = '/bin/oci-network-config' -vnic_fields = ['state', - 'link', - 'status', - 'ipaddress', - 'vnic', - 'mac', - 'hostname', - 'subnet', - 'routerip', - 'namespace', - 'index', - 'vlantag', - 'vlan'] - - -def parse_args(): - """ - Parse command line parameters. - - Returns - ------- - namespace parsed arguments. - """ - parser = argparse.ArgumentParser(description='Utility for collecting 1 attribute of 1 vnic') - parser.add_argument('-i', '--input_field', - action='store', - type=str, - required=True, - choices=vnic_fields, - help='The vnic field to select the vnic.') - parser.add_argument('-v', '--input-value', - action='store', - type=str, - required=True, - help='The value of the select field.') - parser.add_argument('-o', '--output-field', - choices=vnic_fields, - type=str, - required=True, - help='The field the value requested from.') - return parser - - -def get_vnic_data(index, val, field): - """ - Return val for vnic based on index. - - Parameters - ---------- - index: str - base field name. - val: str - base field value. - field: str - requested field value. - - Returns - ------- - str: the requested value, None if absent. - """ - cmd = [oci_network_path, 'show', '--details', '--output-mode', 'parsable'] - all_vnic_data = subprocess.check_output(cmd).decode('utf-8').splitlines() - - for vnic in all_vnic_data: - vnic_list = vnic.split('#') - if index not in vnic_fields or field not in vnic_fields: - return None - if vnic_list[vnic_fields.index(index)] == val: - return vnic_list[vnic_fields.index(field)] - return None - - -def main(): - """ - main - - Returns - ------- - No retunr value. - """ - parser = parse_args() - args = parser.parse_args() - print(get_vnic_data(args.input_field, args.input_value, args.output_field)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/automation/oci_utils_pool_data.py b/tests/automation/oci_utils_pool_data.py deleted file mode 100755 index 84006952..00000000 --- a/tests/automation/oci_utils_pool_data.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Find a the value af an attribute of a kvm pool based on the value of an attribute of the volume. -""" -import argparse -import subprocess -import sys - -oci_kvm_path = '/bin/oci-kvm' -pool_fields = ['name', - 'uuid', - 'autostart', - 'active', - 'persistent', - 'volumes', - 'state', - 'capacity', - 'allocation', - 'available'] - - -def parse_args(): - """ - Parse command line parameters. - - Returns - ------- - namespace parsed arguments. - """ - choicelist = pool_fields - parser = argparse.ArgumentParser(description='Utility for collecting 1 attribute of 1 pool') - parser.add_argument('-i', '--input_field', - action='store', - type=str, - required=True, - choices=choicelist, - help='The vnic field to select the pool.') - parser.add_argument('-v', '--input-value', - action='store', - type=str, - required=True, - help='The value of the select field.') - parser.add_argument('-o', '--output-field', - choices=choicelist, - type=str, - required=True, - help='The field the value requested from.') - return parser - - -def get_pool_data(index, val, field): - """ - Return val for volume based on index. - - Parameters - ---------- - index: str - base field name. - val: str - base field value. - field: str - requested field value. - - Returns - ------- - str: the requested value, None if absent. - """ - cmd = [oci_kvm_path, 'list-pool', '--output-mode', 'parsable'] - all_pool_data = subprocess.check_output(cmd).decode('utf-8').splitlines() - - for pool in all_pool_data: - pool_list = pool.split('#') - if index not in pool_fields or field not in pool_fields: - return None - if pool_list[pool_fields.index(index)] == val: - return pool_list[pool_fields.index(field)] - return None - - -def main(): - """ - main - - Returns - ------- - No retunr value. - """ - parser = parse_args() - args = parser.parse_args() - print(get_pool_data(args.input_field, args.input_value, args.output_field)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/automation/oci_utils_test_instance.py b/tests/automation/oci_utils_test_instance.py deleted file mode 100755 index c25052ba..00000000 --- a/tests/automation/oci_utils_test_instance.py +++ /dev/null @@ -1,1508 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -import argparse -import errno -import getpass -import inspect -import json -import logging -import os -import re -import shutil -import socket -import sys -import termios -import tty -from datetime import datetime -from subprocess import call - -import oci - -# -# locale -lc_all = 'en_US.UTF8' - -software_tree = 'git_repo' -logdir = 'logs' -autotestdir = 'autotests' -tfvars_file = 'instance_variables' -default_log = 'instance_config.log' -config_log = '' - -default_values = { - "os_user": "whocares", - "os_user_home": "whocares", - "auth": "whocares", - "user_ocid": "whocares", - "server_ip": "whocares", - "fingerprint": "whocares", - "oci_private_key": "whocares", - "tenancy_ocid": "whocares", - "region": "whocares", - "ssh_public_key": "whocares", - "ssh_private_key": "whocares", - "compartment_ocid": "whocares", - "source_ocid": "whocares", - "subnet_ocid": "whocares", -# "vcn_ocid": "whocares", -# "network_compartment_ocid": "whocares", - "vnic_display_name": "whocares", - "availability_domain": "whocares", - "instance_display_name": "whocares", - "shape": "whocares", -# "authentication": "whocares", - "source_type": "whocares", - "remote_user": "whocares", -# "autotest_root": "whocares", - "log_file_path": "/logs", - "script_path": "whocares", -# "dns_search_domains" : ".oracle.com", -# "dns_server_ip" : "100.110.7.250", -# "http_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", -# "https_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", -# "http_no_proxy": "169.254.169.254,.oraclecloud.com,.oraclecorp.com,.us.oracle.com" -} - -_logger = logging.getLogger(__name__) - - -def print_g(msg, term=True, destination=None): - """ - Write msg to stdout and to file. - - Parameters - ---------- - msg: str - The text. - term: bool - If true, write to stdout. - destination: str - Path of destination file. - - Returns - ------- - No return value. - """ - if term: - print('%s' % msg) - if not bool(destination): - destination = config_log - with open(destination, 'a') as f: - f.write('%s\n' % msg) - f.flush() - - -def print_g40(head, msg, term=True, destination=None): - """ - Write a message %40s: msg to stdout and file. - - Parameters - ---------- - head: str - The head. - msg: str - The text. - term: bool - If true, write to stdout. - destination: str - Path of destination file. - - Returns - ------- - No return value. - """ - print_g('%40s: %s' % (head, msg), term, destination) - - -def parse_args(): - """ - Parse the command line arguments. - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(description='Configure oci utils auto test instance.') - parser.add_argument('-n', '--name', - action='store', - dest='display_name', - help='The display name of the instance to create. There is no default, ' - 'if not provided, the script asks for it.') - parser.add_argument('-p', '--profile', - action='store', - dest='profile', - default='DEFAULT', - help='The profile in the cli/sdk config file, default is DEFAULT.') - parser.add_argument('-c', '--config', - action='store', - dest='configfile', - default='~/.oci/config', - help='The cli/sdk config file, default is ~/.oci/config.') - parser.add_argument('-d', '--data-directory', - action='store', - dest='datadir', - default='_DDDD_', - help='Root directory with data for auto test run, default is ~//data.') - parser.add_argument('-f', '--var-file', - action='store', - dest='varfilename', - default=tfvars_file, - help='filename to store the variables; the extension .tfvars.json is added automatically.') - parser._optionals.title = 'Arguments' - args = parser.parse_args() - return args - - -def _clear(): - """ - Clear screen. - - Returns - ------- - bool: True - """ - _ = call('clear' if os.name == 'posix' else 'cls') - return True - - -def _is_int(string_data): - """ - Verifies if string is a valid int. - - Parameters - ---------- - string_data: str - The string to be evaluated. - - Returns - ------- - bool: True on success, false otherwise. - """ - return re.match(r"[-+]?\d+$", string_data) is not None - - -def _get_current_user(): - """ - Get the current username. - - Returns - ------- - str: the username. - """ - return getpass.getuser() - - -def _get_current_user_home(): - """ - Get the home directory of the current user. - - Returns - ------- - str: the full path of the home directory. - """ - return os.path.expanduser('~') - - -def _from_stdin(prompt, default=None): - """ - Read from stdin, if default is not set to None, some input is expected. - - Parameters - ---------- - prompt: str - The stdin prompt. - default: - Default value. - - Returns - ------- - value read - """ - while True: - return_val = input('%-40s: ' % prompt) - if bool(return_val): - return return_val - if default is not None: - return default - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def initialise_log(base_dir, *args): - """ - Initialise the logfile. - - Parameters - ---------- - base_dir: str - Path of the log directory. - args: tuple - Log file path base. - - Returns - ------- - str: full path of the log file. - """ - now = datetime.now() - log_path = base_dir - for dirfrag in list(args): - log_path = os.path.join(log_path, dirfrag) - os.makedirs(log_path, exist_ok=True) - global config_log - config_log = os.path.join(log_path, default_log + '_' + now.strftime('%Y%m%d%H%M')) - with open(config_log, 'w') as f: - f.write('') - f.flush() - return config_log - - -def _select_from(some_list, prompt, default_val=0): - """ - Select an item from a list. - - Parameters - ---------- - some_list: list - list of items. - prompt: str - prompt - default_val: int - default index value if no input. - - Returns - ------- - The list element. - """ - while 1 == 1: - selected_nb = input("%s ==> " % prompt) - if not bool(selected_nb): - selected_nb = str(default_val) - if _is_int(selected_nb): - select_index = int(selected_nb) - if 0 <= select_index < len(some_list): - break - print_g('Index %d out of range.' % select_index) - else: - print_g('Invalid input: %s' % selected_nb) - _logger.debug('Selected %s', some_list[select_index]) - return some_list[select_index] - - -def _test_softwaretree_defined(root_dir): - """ - Verify if software_tree is defined. - - Parameters - ---------- - root_dir: str - user home directory - - Returns - ------- - bool: True on success, False otherwise. - """ - return os.path.isdir(os.path.join(root_dir, software_tree)) - - -def _create_dir(dirname, backup=False): - """ - Create a directory, make a backup copy if already exists. - - Parameters - ---------- - dirname: str - Full path - backup: bool - If True, make a backup if already exists. - Returns - ------- - bool: True on success, false otherwise. - """ - try: - if backup: - if os.path.exists(dirname): - bck_name = dirname + '_%s' % datetime.now().strftime('%Y%m%d_%H%M') - os.rename(dirname, bck_name) - print_g('Renamed %s to %s' % (dirname, bck_name), term=False) - os.makedirs(dirname) - _logger.debug('Created %s', dirname) - except OSError as e: - if e.errno != errno.EEXIST: - print_g('Failed to create %s' % dirname, term=False) - return False - _logger.warning('%s already exists, might cause problems.', dirname) - return True - - -def get_configdata(profile, configfile='~/.oci/config'): - """ - Read the oci sdk/cli config file. - - Parameters - ---------- - profile: str - the config profile. - configfile: str - the path of the configfile. - Returns - ------- - dict: the config data. - """ - sdkconfigfile = configfile - if configfile.startswith('~/'): - sdkconfigfile = os.path.expanduser('~') + configfile[1:] - config = oci.config.from_file(file_location=sdkconfigfile, profile_name=profile) - return config - - -class autotesttfvars: - """ - Manipulate the tfvar.json file. - """ - def __init__(self, tfvars_file): - """ - Initialise. - - Parameters - ---------- - tfvars_file: str - Full path of the tfvar.json file. - # sdkconfig: dict - # Contents of the sdk config file. - """ - self.json_file = tfvars_file - # self.sdkconfig = sdkconfig - try: - with open(self.json_file, 'rb') as tfvj: - self.jsondata = json.load(tfvj) - print_g40('Parameters', 'read %s' % self.json_file) - except Exception as e: - # - # Failed to read variable def file, falling back to idle defaults. - # print_g('Failed to read %s, Creating default' % self.json_file) - print_g40('Parameters', 'created %s from default' % self.json_file) - self.jsondata = default_values - - def __enter__(self): - return self - - def __exit__(self, xtype, value, traceback): - try: - with open(self.json_file, 'w') as tfvj: - json.dump(self.jsondata, tfvj, indent=4) - return True - except Exception as e: - raise Exception('Failed to write %s:' % self.json_file) from e - - def update_json_with_config(self, sdk_config): - """ - Update tf.json file with .oci/config data. - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g('') - print_g40('Collecting data from sdk config file:', '') - self.jsondata['user_ocid'] = sdk_config['user'] - print_g40('user ocid', sdk_config['user']) - self.jsondata['fingerprint'] = sdk_config['fingerprint'] - print_g40('fingerprint', sdk_config['fingerprint']) - self.jsondata['oci_private_key'] = sdk_config['key_file'] - print_g40('oci_private_key', sdk_config['key_file']) - self.jsondata['tenancy_ocid'] = sdk_config['tenancy'] - print_g40('tenancy_ocid', sdk_config['tenancy']) - self.jsondata['region'] = sdk_config['region'] - print_g40('region', sdk_config['region']) - if _read_yn('Agree?', default_yn=True): - return True - return False - - def update_user(self): - """ - Update tf.json file with user related data. - - Returns - ------- - bool: True on success, False otherwise. - """ - # - # os user data - current_user = _get_current_user() - if bool(self.jsondata['os_user']): - if _read_yn('\nReplace %s by %s' % (self.jsondata['os_user'], current_user), default_yn=True): - self.jsondata['os_user'] = current_user - else: - self.jsondata['os_user'] = _from_stdin('os user', default=current_user) - - current_user_home = _get_current_user_home() - if bool(self.jsondata['os_user_home']): - if _read_yn('Replace %s by %s' % (self.jsondata['os_user_home'], current_user_home), default_yn=True): - self.jsondata['os_user_home'] = current_user_home - else: - self.jsondata['os_user_home'] = _from_stdin('os user home', default=current_user_home) - # - # ssh keys - pub_key = current_user_home + '/.ssh/id_rsa.pub' - if bool(self.jsondata['ssh_public_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_public_key'], pub_key), default_yn=True): - self.jsondata["ssh_public_key"] = pub_key - else: - self.jsondata['ssh_public_key'] = _from_stdin('ssh public key', default=pub_key) - priv_key = current_user_home + '/.ssh/id_rsa' - if bool(self.jsondata['ssh_private_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_private_key'], priv_key), default_yn=True): - self.jsondata["ssh_private_key"] = priv_key - else: - self.jsondata['ssh_private_key'] = _from_stdin('ssh private key', default=priv_key) - # - # ip V4 address - thisipv4 = socket.gethostbyname(socket.gethostname()) - if bool(self.jsondata['server_ip']): - if _read_yn('Replace %s by %s' % (self.jsondata['server_ip'], thisipv4), default_yn=True): - self.jsondata['server_ip'] = thisipv4 - else: - self.jsondata['server_ip'] = _from_stdin('server ip address', default=thisipv4) - return True - - def update_image(self, image_data): - """ - Update tf.json file with image related data. - - Parameters - ---------- - image_data: dict - The image data - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g(image_data) - for k, v in image_data.items(): - print_g('%30s %s' % (k, v)) - self.jsondata[k] = v - - return True - - def update_varia(self, variadata): - """ - Update various data. - - Parameters - ---------- - variadata: dict - The various data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in variadata.items(): - print_g40(var_key, var_val) - self.jsondata[var_key] = _get_string('%s' % var_key) - return True - - def update_gen_data(self, gendata): - """ - Update tf.json with generic data. - - Parameters - ---------- - gendata: dict - The generic data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in gendata.items(): - self.jsondata[var_key] = var_val - return True - - -def _read_nb(prompt, min_val=1, max_val=64, default_val=1): - """ - Read an integer number from stdin. - - Parameters - ---------- - prompt: str - prompt - min_val: int - the smallest possible value. - max_val: int - the largest possible value. - default_val: int - default value if no input. - - Returns - ------- - int: the number. - """ - while 1 == 1: - read_nb = input("%s ==> " % prompt) - if not bool(read_nb): - read_nb = int(default_val) - if _is_int(read_nb): - rread_nb = int(read_nb) - if min_val <= rread_nb <= max_val: - break - print_g('Value %d out of range.' % rread_nb) - else: - print_g('Invalid input: %s' % read_nb) - _logger.debug('Value read from stdin: %d' % rread_nb) - return rread_nb - - -def select_compartment(config_dict, prompt): - """ - Select a compartment in the tenancy. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - - prompt: str - The prompt - Returns - ------- - dict: the data of the compartment. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_compartments = oci_identity.list_compartments(config_dict['tenancy']) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for comp in oci_compartments.data: - print_g('%4d %-30s %s' % (oci_compartments.data.index(comp), comp.name, comp.id)) - return _select_from(oci_compartments.data, prompt) - - -def get_compartment(config_dict, prompt): - """ - Get compartment ocid in a loop. - - Parameters - ---------- - config_dict dict - The oci configuration file data. - - prompt: str - The prompt - - Returns - ------- - str: the ocid of the compartment. - """ - yn = False - _clear() - while not yn: - compartment = select_compartment(config_dict, prompt) - print_g(compartment, term=False) - print_g('Selected compartment: %s\n' % compartment.name) - yn = _read_yn('Continue?', default_yn=True) - return compartment.id - - -def select_vcn(config_dict, compartment_id): - """ - Select a VCN. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the VCN - """ - try: - oci_vncclient = oci.core.VirtualNetworkClient(config_dict) - oci_vcns = oci_vncclient.list_vcns(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for vcn in oci_vcns.data: - print_g('%4d %-30s %s' % (oci_vcns.data.index(vcn), vcn.display_name, vcn.id)) - return _select_from(oci_vcns.data, 'Select VCN for instance.') - - -def get_vcn(config_dict, comp_id): - """ - Get the vcn id in a loop. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - comp_id: str - The network compartment ocid - - Returns - ------- - str: the vcn id - """ - yn = False - _clear() - while not yn: - vcn = select_vcn(config_dict, comp_id) - print_g(vcn, term=False) - print_g('Selected VCN: %s\n' % vcn.display_name) - yn = _read_yn('Continue?', default_yn=True) - return vcn.id - - -def select_subnet(config_dict, compartment_id, vcn_id): - """ - Select a subnet. - - Parameters¶ - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The network compartment ocid - - Returns - ------- - dict: the subnet - """ - try: - oci_subnetclient = oci.core.VirtualNetworkClient(config_dict) - oci_subnets = oci_subnetclient.list_subnets(compartment_id, vcn_id=vcn_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for subnet in oci_subnets.data: - print_g('%4d %-30s %s' % (oci_subnets.data.index(subnet), subnet.display_name, subnet.id)) - return _select_from(oci_subnets.data, 'Select subnet instance.') - - -def get_subnet(config_dict, comp_id, vcn_id): - """ - Get the subnet id in a loop. - Parameters - ---------- - config_dict: dict - The oci configuration file data. - comp_id: str - The network compartment ocid. - vcn_id: str - The vcn ocid. - - Returns - ------- - str: the subnet id. - """ - yn = False - _clear() - while not yn: - subnet = select_subnet(config_dict, comp_id, vcn_id) - print_g(subnet, term=False) - print_g('Selected subnet: %s\n' % subnet.display_name) - yn = _read_yn('Continue?', default_yn=True) - return subnet.id - - -def select_image(config_dict, compartment_id): - """ - Select an image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the image - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - # oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id).data - - oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Zero').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Custom').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Oracle Linux').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Oracle Autonomous Linux').data - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for image in oci_images_data: - # print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.id)) - print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.operating_system)) - image_data = _select_from(oci_images_data, 'Select Image') - print_g(image_data, term=False) - return image_data - - -def get_public_ip(): - """ - Request for public ip. - - Returns - ------- - bool: true or false. - """ - yn = False - _ = _clear() - while not yn: - pubip = _read_yn('Assign a public IPv4 address?') - print_g('Public IP: %s' % 'True' if pubip else "False") - yn = _read_yn('Continue?', default_yn=True) - return pubip - - -def get_image(cfg_dict, comp_id): - """ - Get the source image ocid. - - Parameters - ---------- - cfg_dict: dict - The oci configuration file data. - comp_id: str - The compartment ocid - - Returns - ------- - str: the source image ocid. - """ - yn = False - _clear() - while not yn: - image = select_image(cfg_dict, comp_id) - print_g(image, term=False) - print_g('Selected image: %s\n' % image.display_name) - yn = _read_yn('Continue?', default_yn=True) - return image.id - - -def select_availability_domain(config_dict, compartment_id): - """ - Select an availability domain. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the availability domain. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_availability_domains = oci_identity.list_availability_domains(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for domain in oci_availability_domains.data: - print_g('%4d %-30s %s' % (oci_availability_domains.data.index(domain), domain.name, domain.id)) - return _select_from(oci_availability_domains.data, 'Select availability domain.') - - -def get_availability_domain(config_dict, compart_id): - """ - Get compartment ocid in a loop. - - Parameters - ---------- - config_dict dict - The oci configuration file data. - - compart_id: str - The ocid of the compartment. - - Returns - ------- - str: the name of the availability domain. - """ - yn = False - _clear() - while not yn: - domain = select_availability_domain(config_dict, compart_id) - print_g(domain, term=False) - print_g('Selected availability domain: %s\n' % domain.name) - yn = _read_yn('Continue?', default_yn=True) - return domain.name - - -def select_shape(config_dict, image_ocid): - """ - Select a compatible shape for the image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - image_ocid: str - The ocid pf the image. - - Returns - ------- - The shape. - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - oci_shapes = oci_imageclient.list_image_shape_compatibility_entries(image_ocid) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for shape_dict in oci_shapes.data: - print_g('%4d %-30s' % (oci_shapes.data.index(shape_dict), shape_dict.shape)) - return _select_from(oci_shapes.data, 'Select shape.') - - -def get_shape(cfg_dict, img_ocid): - """ - Get the ocid of the shape to use. - - Parameters - ---------- - cfg_dict: dict - The oci configuration file data. - img_ocid:str - The ocid pf the image. - - Returns - ------- - The shape to use. - """ - yn = False - _clear() - while not yn: - shape = select_shape(cfg_dict, img_ocid) - print_g(shape, term=False) - print_g('Selected shape: %s\n' % shape.shape) - yn = _read_yn('Continue?', default_yn=True) - return shape.shape - - -def get_flex_memory(shape): - """ - Get the memory size for a flex shape. - - Parameters - ---------- - shape: str - The shape name. - - Returns - ------- - int: the memory size in GB - """ - yn = False - _clear() - while not yn: - mem_size = _read_nb('Memory for %s in GB' % shape, default_val=4, max_val=256) - print_g(mem_size, term=False) - print_g('Memory for %s: %dGB' % (shape, mem_size)) - yn = _read_yn('Continue?', default_yn=True) - return mem_size - - -def get_flex_cpus(shape): - """ - Get the number of cpus for a flex shape. - - Parameters - ---------- - shape: str - The shape name. - - Returns - ------- - int: the number of cpus. - """ - yn = False - _clear() - while not yn: - nb_cpus = _read_nb('The number of ocpus for %s' % shape, default_val=2, max_val=18) - print_g(nb_cpus, term=False) - print_g('The number of ocpus for %s: %s' % (shape,nb_cpus)) - yn = _read_yn('Continue?', default_yn=True) - return nb_cpus - - -def _get_display_name(): - """ - Read instance display name from stdin. - - Returns - ------- - str: the display name. - """ - return input('Instance Display Name: ') - - -def _get_authentication_method(): - """ - Determine the authentication method. - - Returns - ------- - str: the authentication method. - """ - _ = _clear() - print_g('Authentication method.\n', term=True) - auth_methods = ['ApiKey', 'InstancePrincipal'] - yn = False - while not yn: - for authm in auth_methods: - print_g('%4d: %s' % (auth_methods.index(authm), authm)) - method = _select_from(auth_methods, 'Authentication method:') - print_g('Selected authentication method: %s\n' % method) - yn = _read_yn('Continue?', default_yn=True) - return method - - -def _get_remote_user(): - """ - Get the remote username. - - Returns - ------- - str: the username. - """ - yn = False - _clear() - while not yn: - rem_user = input('Remote User Name: ') - print_g(rem_user, term=False) - print_g('Remote User Name: %s' % rem_user) - yn = _read_yn('Continue?', default_yn=True) - return rem_user - - -def _get_proxy(default_proxy, prompt): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The http proxy url. - """ - _clear() - new_url = default_proxy - yn = False - while not yn: - new_urlx = input('%s\n [%s] (ENTER to accept default):' % (prompt,new_url)) - if not bool(new_urlx): - return(new_url) - new_url = new_urlx - print_g(new_url, term=False) - print_g('%s: %s' % (prompt,new_url)) - yn = _read_yn('Continue?', default_yn=True) - return new_url - - -def _get_log_file(default_log_file): - """ - Get the log file path. - - Parameters - ---------- - default_log_file: str - The default path. - - Returns - ------- - The path tot the log file. - """ - _clear() - new_log = default_log_file - yn = False - while not yn: - new_logx = input('log file path\n [%s] (ENTER to accept default):' % default_log_file) - if not bool(new_logx): - return(new_log) - new_log = new_logx - print_g(new_log, term=False) - print_g('new log file: %s' % new_log) - yn = _read_yn('Continue?', default_yn=True) - return new_log - - -def _get_string(default_name, prompt): - _clear() - new_string = default_name - yn = False - while not yn: - new_stringx = input('%s\n [%s] (ENTER to accept default):' % (prompt,default_name)) - if not bool(new_stringx): - return(new_string) - new_display_name = new_stringx - print_g(new_string, term=False) - print_g('new value: %s' % new_string) - yn = _read_yn('Continue?', default_yn=True) - return new_string - - -def _get_dns_search_domain(): - """ - Get the dns search domain. - - Returns - ------- - str: The dns search domain, default is retrieved from /etc/resolv.conf. - """ - # _clear() - resolv_file = '/etc/resolv.conf' - search_domain = 'whocares' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'search' in rf_line: - search_domain = rf_line.split()[1] - break - return search_domain - - -def _get_dns_server_ip(): - """ - Get the dns server ipv4 - - Returns - ------- - str: The dns server ipv4 address., default is retrieved from /etc/resolv.conf. - """ - # _clear() - resolv_file = '/etc/resolv.conf' - nameserver = '8.8.8.8' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'nameserver' in rf_line: - nameserver = rf_line.split()[1] - break - return nameserver - - -def get_generic_data(data): - """ - Get generic variables. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the generic variables. - """ - gen_data = { - # 'instance_display_name': _get_display_name(), - 'instance_display_name': data['instance_display_name'], - 'vnic_display_name': data['instance_display_name'], - 'auth': _get_authentication_method(), - 'remote_user': _get_remote_user(), - # 'http_proxy_url': _get_proxy(default_values['http_proxy_url'], 'http proxy url'), - # 'https_proxy_url': _get_proxy(default_values['https_proxy_url'], 'https proxy url'), - # 'http_no_proxy': _get_no_proxy(default_values['http_no_proxy']), - # 'http_no_proxy': _get_proxy(default_values['http_no_proxy'], 'no proxy'), - 'log_file_path': _get_log_file(default_values['log_file_path']), - # 'dns_search_domains': _get_dns_search_domain(), - # 'dns_server_ip': _get_dns_server_ip(), - 'script_path': data['script_path'] - } - return gen_data - - -def init_struct(instance_name): - """ - Initialise config struct. - - Parameters - ---------- - instance_name: str - The instance display name. - - Returns - ------- - dict: the config structure. - """ - # - # exec dir - data = dict() - exec_dir = inspect.getfile(inspect.currentframe()) - data['instance_display_name'] = instance_name - print_g40('Instance', data['instance_display_name']) - data['exec_dir'] = os.path.dirname(exec_dir) - print_g40('Bin Directory', data['exec_dir']) - return data - - -def get_user_data(data): - """ - Collect operator data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - data['operator'] = _get_current_user() - data['operator_home'] = _get_current_user_home() - return data - - -def get_test_instance(data): - """ - Define the directories involved. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - # - # test instance root - data['test_instance_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name']) - print_g40('Tests Instance Location', data['test_instance_dir']) - # - # base instance destination - data['base_instance_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'base_instance') - print_g40('Base_Instance', data['base_instance_dir']) - # - # scripts source - data['script_location'] = os.path.join(data['operator_home'], software_tree, 'tests', 'automation', 'data', 'scripts') - print_g40('Scripts Location', data['script_location']) - # - # scripts destination - data['script_path'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'sh_scripts') - print_g40('Scripts Directory', data['script_path']) - # - # data - instance variables destination - data['data_dir'] = os.path.join(data['operator_home'], autotestdir, data['instance_display_name'], 'data') - data['tfvarsfile'] = os.path.join(data['data_dir'], tfvars_file) - return data - - -def create_directories(data, args): - """ - Create directories for scripts. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - if args.datadir != '_DDDD_': - data['def_data_dir'] = args.datadir + '/data' - if not _create_dir(data['test_instance_dir']): - sys.exit(1) - print_g40('Created', data['test_instance_dir']) - if not _create_dir(data['script_path']): - sys.exit(1) - print_g40('Created', data['script_path']) - if not _create_dir(data['data_dir']): - sys.exit(1) - print_g40('Created', data['data_dir']) - if not _create_dir(data['base_instance_dir']): - sys.exit(1) - print_g40('Created', data['base_instance_dir']) - return data - - -def create_sh_scripts(data): - """ - Copy script to test instance environment. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - bool: True on success, False otherwise. - """ - try: - for script in os.listdir(data['script_location']): - print_g40('Copy', os.path.join(data['script_location'],script)) - shutil.copy(os.path.join(data['script_location'], script), data['script_path']) - return True - except Exception as e: - print_g('%s' % str(e)) - return False - - -def main(): - """ - Configure an instance for auto tests. - - Returns - ------- - int: 0 on success, raises exception on failure. - """ - # - # locale - os.environ['LC_ALL'] = "%s" % lc_all - # - # parse the commandline - args = parse_args() - # - # clear - _ = _clear() - # - # user data - current_user = _get_current_user() - current_user_home = _get_current_user_home() - # - # instance name to create - instance_display_name = args.display_name if args.display_name is not None else _get_display_name() - # - # create log directory - global config_log - config_log = initialise_log(current_user_home, logdir, instance_display_name) - debug_log = initialise_log(current_user_home, logdir, instance_display_name) - # - # user data - print_g40('Current User', current_user) - print_g40('Current user home', current_user_home) - # - # initialise logging - logging.basicConfig(filename=debug_log, - level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s (%(module)s:%(lineno)s) - %(message)s') - # - # exec dir - config_data = init_struct(instance_display_name) - # - # current user - config_data = get_user_data(config_data) - # - # check directory with unittests. - if not _test_softwaretree_defined(config_data['operator_home']): - sys.exit('Software tree %s not present.' % software_tree) - # - # initialise data structure - image_data = dict() - # - # test environment - config_data = get_test_instance(config_data) - # - # create directories - config_data = create_directories(config_data, args) - # - # scripts - if not create_sh_scripts(config_data): - sys.exit('Failed to copy scripts') - # - # init tfvars file - tfvarsfile = os.path.join(config_data['data_dir'], args.varfilename + '.tfvars.json') - cfg_dict = get_configdata(args.profile, args.configfile) - # - # - with autotesttfvars(tfvarsfile) as atfv: - if not atfv.update_json_with_config(cfg_dict): - sys.exit("Failed to update json.") - print_g40('Updated variables with config data', 'ok') - res = atfv.update_user() - print_g40('Updated variables with operator data', 'ok') - # - # Instance compartment - image_data['compartment_ocid'] = get_compartment(cfg_dict, 'Select compartment for the instance:') - # - # Availability domain - image_data['availability_domain'] = get_availability_domain(cfg_dict, image_data['compartment_ocid']) - # - # Network compartment - # image_data['network_compartment_ocid'] = get_compartment(cfg_dict, 'Select compartment for the network:') - network_compartment_ocid = get_compartment(cfg_dict, 'Select compartment for the network:') - # - # Virtual Cloud Network - # image_data['vcn_ocid'] = get_vcn(cfg_dict, image_data['network_compartment_ocid']) - # image_data['vcn_ocid'] = get_vcn(cfg_dict, network_compartment_ocid) - image_data_vcn_ocid = get_vcn(cfg_dict, network_compartment_ocid) - # - # Subnets - # image_data['subnet_ocid'] = get_subnet(cfg_dict, image_data['network_compartment_ocid'], image_data['vcn_ocid']) - image_data['subnet_ocid'] = get_subnet(cfg_dict, network_compartment_ocid, image_data_vcn_ocid) - # - # Public ip - image_data['assign_public_ip'] = get_public_ip() - # - # Type - image_data['source_type'] = 'image' - # - # Images - image_data['source_ocid'] = get_image(cfg_dict, image_data['compartment_ocid']) - # - # Shape - image_data['shape'] = get_shape(cfg_dict, image_data['source_ocid']) - # - # Flex shape: get memory size and number of cpus - if bool(re.search('Flex', image_data['shape'])): - image_data['instance_flex_memory_in_gbs'] = get_flex_memory(image_data['shape']) - image_data['instance_flex_ocpus'] = get_flex_cpus(image_data['shape']) - # - # various data - # varia_data = { - # 'vnic_display_name': default_values['vnic_display_name'] - # } - - # with autotesttfvars(tfvarsfile) as atfv: - # res = atfv.update_varia(varia_data) - # print_g('Updated various data.') - # - # get generic variables - gen_data = get_generic_data(config_data) - # - # update tfvars file - with autotesttfvars(tfvarsfile) as atfv: - res = atfv.update_image(image_data) - print_g('Updated variables with image data.') - res = atfv.update_gen_data(gen_data) - print_g('Updated variables with generic data.') - # - # - print_g('Wrote configuration to %s' % tfvarsfile) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/automation/templates/tf_apikey b/tests/automation/templates/tf_apikey deleted file mode 100644 index 63283cbf..00000000 --- a/tests/automation/templates/tf_apikey +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_sdk_config" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.oci_private_key - destination = "/tmp/oci_private_key.pem" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_PUBIP_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_PUBIP_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.oci", - "/bin/sudo --preserve-env cp /tmp/oci_private_key.pem /root/.oci/$(basename ${var.oci_private_key})", - "/bin/sudo --preserve-env echo [DEFAULT] > /tmp/config", - "/bin/sudo --preserve-env echo user=${var.user_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo fingerprint=${var.fingerprint} >> /tmp/config", - "/bin/sudo --preserve-env echo key_file=/root/.oci/$(basename ${var.oci_private_key}) >> /tmp/config", - "/bin/sudo --preserve-env echo tenancy=${var.tenancy_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo region=${var.region} >> /tmp/config", - "/bin/sudo cp /tmp/config /root/.oci/config", - "/bin/sudo chmod -R 600 /root/.oci/" - ] - } -} diff --git a/tests/automation/templates/tf_data b/tests/automation/templates/tf_data deleted file mode 100644 index 99a130df..00000000 --- a/tests/automation/templates/tf_data +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} diff --git a/tests/automation/templates/tf_main b/tests/automation/templates/tf_main deleted file mode 100644 index c39b92d8..00000000 --- a/tests/automation/templates/tf_main +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//FLEXvariable "instance_flex_memory_in_gbs" { -//FLEX description = "instance memorry size in GB." -//FLEX type = number -//FLEX} - -//FLEXvariable "instance_flex_ocpus" { -//FLEX description = "amount of instance ocpus." -//FLEX type = number -//FLEX} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "script_path" { - description = "path to bash script direcory" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape -//FLEX instance_flex_memory_in_gbs = var.instance_flex_memory_in_gbs -//FLEX instance_flex_ocpus = var.instance_flex_ocpus - source_ocid = var.source_ocid - source_type = var.source_type - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path - script_path = var.script_path -} diff --git a/tests/automation/templates/tf_output b/tests/automation/templates/tf_output deleted file mode 100644 index 242b4dc9..00000000 --- a/tests/automation/templates/tf_output +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - value = module.base_instance.instance_private_ip -} - -//PUBIPoutput "instance_public_ip" { -//PUBIP value = module.base_instance.instance_public_ip -//PUBIP} - -output "boot_volume_ocid" { - value = module.base_instance.boot_volume_ocid -} - -output "instance_ocid" { - value = module.base_instance.instance_ocid -} \ No newline at end of file diff --git a/tests/automation/templates/tf_test b/tests/automation/templates/tf_test deleted file mode 100644 index 981eabfd..00000000 --- a/tests/automation/templates/tf_test +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "run__TTTT_" { - depends_on = [_BBBB_] - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_private_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "_SSSS_" - ] - } -} \ No newline at end of file diff --git a/tests/automation/templates/tf_version b/tests/automation/templates/tf_version deleted file mode 100644 index 3d2fdf15..00000000 --- a/tests/automation/templates/tf_version +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} \ No newline at end of file diff --git a/tests/test_cli_iscsi_config_create.py b/tests/test_cli_iscsi_config_create.py index 92d424af..048dc5cc 100644 --- a/tests/test_cli_iscsi_config_create.py +++ b/tests/test_cli_iscsi_config_create.py @@ -14,7 +14,6 @@ os.environ['LC_ALL'] = 'en_US.UTF8' os.environ['_OCI_UTILS_DEBUG'] = '1' - def _get_volume_data(volume_data): """ Formats the data list retrieved from show as a dictionary. @@ -31,7 +30,6 @@ def _get_volume_data(volume_data): singlespace = re.compile("\s*,\s*|\s+$") volume_data_dict = dict() ind = 0 - iqn = '-' for y in volume_data: if y.startswith('Currently attached iSCSI') or y.startswith('No iSCSI devices attached'): break @@ -62,7 +60,7 @@ def _get_volume_data(volume_data): if 'OCID' in y: ocid = singlespace.sub(' ', y.split(': ', 1)[1]).strip() cnt += 1 - elif 'iqn' in y: + elif 'IQN' in y: iqn = singlespace.sub(' ', y.split(': ', 1)[1]).strip() cnt += 1 if cnt == 2: @@ -242,7 +240,7 @@ def test_destroy_non_existent(self): this_ocid = uuid.uuid4().hex _show_res('Volume ocid', [this_ocid]) with self.assertRaises(Exception) as e: - destroy_volume_data = subprocess.check_output([self.iscsi_config_path, 'destroy', '--ocids', this_ocid, '--yes']).decode('utf-8').splitlines() + destroy_volume_data = subprocess.check_output([self.iscsi_config_path, 'destroy', '--ocids', this_ocid, '--yes']).decode('utf-8').splitlines() err = e.exception print('Exception %s' % str(err)) except Exception as e: @@ -264,7 +262,7 @@ def test_attach_non_existent(self): this_ocid = uuid.uuid4().hex _show_res('Volume ocid', [this_ocid]) with self.assertRaises(Exception) as e: - attach_volume_data = subprocess.check_output([self.iscsi_config_path, 'attach', '--iqns', this_ocid]).decode('utf-8').splitlines() + attach_volume_data = subprocess.check_output([self.iscsi_config_path, 'attach', '--iqns', this_ocid]).decode('utf-8').splitlines() err = e.exception print('Exception %s' % str(err)) except Exception as e: @@ -286,7 +284,7 @@ def test_detach_non_existent(self): this_iqn = 'iqn.2015-12.com.oracleiaas:' + uuid.uuid4().hex _show_res('Volume ocid', [this_iqn]) with self.assertRaises(Exception) as e: - detach_volume_data = subprocess.check_output([self.iscsi_config_path, 'detach', '--iqns', this_iqn]).decode('utf-8').splitlines() + detach_volume_data = subprocess.check_output([self.iscsi_config_path, 'detach', '--iqns', this_iqn]).decode('utf-8').splitlines() err = e.exception print('Exception %s' % str(err)) except Exception as e: @@ -319,7 +317,7 @@ def test_create_destroy_attach(self): # destroy _show_res('Volume ocid', [new_ocid]) with self.assertRaises(Exception) as e: - destroy_volume_data = subprocess.check_output([self.iscsi_config_path, 'destroy', '--ocids', new_ocid, '--yes']).decode('utf-8').splitlines() + destroy_volume_data = subprocess.check_output([self.iscsi_config_path, 'destroy', '--ocids', new_ocid, '--yes']).decode('utf-8').splitlines() err = e.exception print('Exception %s' % str(err)) # @@ -360,8 +358,7 @@ def test_multiple_create_destroy(self): for vol in vol_list: create_volume_data = subprocess.check_output([self.iscsi_config_path, 'create', '--size', self.volume_size, - '--volume-name', vol, - '--attach-volume']).decode('utf-8').splitlines() + '--volume-name', vol, '--attach-volume']).decode('utf-8').splitlines() _show_res('Volume created', create_volume_data) time.sleep(self.waittime) # @@ -373,8 +370,7 @@ def test_multiple_create_destroy(self): for vol in vol_list: detach_volume_data += self._get_iqn(volume_data, vol) + ',' _show_res('IQN list', [detach_volume_data]) - detach_volume_data = subprocess.check_output([self.iscsi_config_path, 'detach', - '--iqns', detach_volume_data[:-1]]).decode('utf-8').splitlines() + detach_volume_data = subprocess.check_output([self.iscsi_config_path, 'detach', '--iqns', detach_volume_data[:-1]]).decode('utf-8').splitlines() _show_res('Volumes detached', detach_volume_data) time.sleep(self.waittime) # diff --git a/tests/test_cli_metadata.py b/tests/test_cli_metadata.py index a162c0e2..19616f46 100644 --- a/tests/test_cli_metadata.py +++ b/tests/test_cli_metadata.py @@ -50,6 +50,7 @@ agentconfig_key_set = ('monitoringdisabled', 'managementdisabled', 'allpluginsdisabled', + 'pluginsconfig', ) pluginsconfig_key_set = ('name', 'desiredstate', diff --git a/tests/test_cli_network_config_attach.py b/tests/test_cli_network_config_attach.py index 7f2afd99..9486ff99 100644 --- a/tests/test_cli_network_config_attach.py +++ b/tests/test_cli_network_config_attach.py @@ -194,8 +194,7 @@ def test_add_remove_secondary_ip_1(self): time.sleep(self.waittime) self.assertIn('Deconfigure secondary private IP', subprocess.check_output([self.oci_net_config, 'remove-secondary-addr', '--ip-address', new_ip]).decode('utf-8'), 'remove secondary ip failed') time.sleep(self.waittime) - detach_data = subprocess.check_output([self.oci_net_config, 'detach-vnic', '--ocid', vn_ocid]).decode('utf-8') - self.assertIn('is detached', detach_data, '') + self.assertEqual(subprocess.check_output([self.oci_net_config, 'detach-vnic', '--ocid', vn_ocid]).decode('utf-8'), '') time.sleep(self.waittime) except Exception as e: self.fail('Execution oci-network-config attach detach has failed: %s' % str(e)) @@ -213,8 +212,7 @@ def test_attach_detach_vnic_comp(self): self.assertIn('Creating', create_data, 'attach vnic failed') new_ipv4 = _get_ip_from_response(create_data)[0] time.sleep(self.waittime) - detach_data = subprocess.check_output([self.oci_net_config, '--detach-vnic', new_ipv4]).decode('utf-8') - self.assertIn('is detached', detach_data, '') + self.assertEqual(subprocess.check_output([self.oci_net_config, '--detach-vnic', new_ipv4[0]]).decode('utf-8'), '') time.sleep(self.waittime) except Exception as e: self.fail('Execution oci-network-config attach detach in 0.11 compatibility mode has failed: %s' % str(e)) @@ -239,8 +237,7 @@ def test_attach_add_del_ip_detach_vnic_comp(self): del_ip_data = subprocess.check_output([self.oci_net_config, '--del-private-ip', self.extra_ip]).decode('utf-8') self.assertIn('Deconfigure secondary private IP', del_ip_data, 'remove private ip failed') time.sleep(self.waittime) - detach_data =subprocess.check_output([self.oci_net_config, '--detach-vnic', new_ipv4]).decode('utf-8') - self.assertIn('is detached', detach_data, '') + self.assertEqual(subprocess.check_output([self.oci_net_config, '--detach-vnic', new_ipv4]).decode('utf-8'), '') time.sleep(self.waittime) except Exception as e: self.fail('Execution oci-network-config attach detach in 0.11 compatibility mode has failed: %s' % str(e)) diff --git a/tests/test_cli_network_config_configure.py b/tests/test_cli_network_config_configure.py index 70f3d354..717f01ad 100644 --- a/tests/test_cli_network_config_configure.py +++ b/tests/test_cli_network_config_configure.py @@ -12,7 +12,6 @@ import oci_utils.oci_api from tools.oci_test_case import OciTestCase -from pprint import pformat os.environ['LC_ALL'] = 'en_US.UTF8' os.environ['_OCI_UTILS_DEBUG'] = '1' @@ -117,26 +116,22 @@ def test_configure_comp(self): No return value. """ try: - create_data = subprocess.check_output([self.oci_net_config, '--create-vnic']).decode('utf-8').splitlines() - print(create_data[0]) - self.assertIn('Creating', create_data[0], 'attach vnic failed') - new_ipv4 = _get_ip_from_response(create_data[0])[0] - print(new_ipv4) + create_data = subprocess.check_output([self.oci_net_config, '--create-vnic']).decode('utf-8') + print(create_data) + self.assertIn('Creating', create_data, 'attach vnic failed') + new_ipv4 = _get_ip_from_response(create_data)[0] time.sleep(self.waittime) - deconfig_data = subprocess.check_output([self.oci_net_config, '--deconfigure']).decode('utf-8').splitlines() - print(deconfig_data) + print(subprocess.check_output([self.oci_net_config, '--deconfigure']).decode('utf-8')) time.sleep(self.waittime) - config_data = subprocess.check_output([self.oci_net_config, '--configure']).decode('utf-8').splitlines() - print(config_data) + print(subprocess.check_output([self.oci_net_config, '--configure']).decode('utf-8')) time.sleep(self.waittime) - exclude_output = subprocess.check_output([self.oci_net_config, '--configure', '-X', new_ipv4]).decode('utf-8').splitlines() + exclude_output = subprocess.check_output([self.oci_net_config, '--configure', '-X', new_ipv4]).decode('utf-8') print(exclude_output) - include_output = subprocess.check_output([self.oci_net_config, '--configure', '-I', new_ipv4]).decode('utf-8').splitlines() + include_output = subprocess.check_output([self.oci_net_config, '--configure', '-I', new_ipv4]).decode('utf-8') print(include_output) - delete_data = subprocess.check_output([self.oci_net_config, '--detach-vnic', new_ipv4]).decode('utf-8').splitlines() - print(delete_data[0]) - detach_data = subprocess.check_output([self.oci_net_config, '--show']).decode('utf-8').splitlines() - self.assertNotIn(new_ipv4, detach_data[0], 'detach vnic failed') + delete_data = subprocess.check_output([self.oci_net_config, '--detach-vnic', new_ipv4 ]).decode('utf-8') + print(delete_data) + self.assertNotIn(new_ipv4, subprocess.check_output([self.oci_net_config, '--show']).decode('utf-8'), 'detach vnic failed') except Exception as e: self.fail('Execution oci-network-config configure in compatibility mode has failed: %s' % str(e)) @@ -145,48 +140,35 @@ def test_configure(self): Test basic run of configure command. We do not check out. Returns - + ------- No return value. """ try: - create_data = subprocess.check_output([self.oci_net_config, 'attach-vnic', '--name', self.vnic_name]).decode('utf-8').splitlines() - print(create_data) - self.assertIn('Creating', create_data[0], 'attach vnic failed') + create_data = subprocess.check_output([self.oci_net_config, 'attach-vnic', '--name', self.vnic_name]).decode('utf-8') + self.assertIn('Creating', create_data, 'attach vnic failed') time.sleep(self.waittime) vn_ocid = self._get_vnic_ocid(self.vnic_name) - print(vn_ocid) - new_ipv4 = _get_ip_from_response(create_data[0])[0] - print(new_ipv4) - print(subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8').splitlines()) - config_output = subprocess.check_output([self.oci_net_config, 'configure']).decode('utf-8').splitlines() - print(config_output[0]) - self.assertNotIn('ADD', config_output, 'configuration failed') + new_ipv4 = _get_ip_from_response(create_data)[0] + print(subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8')) + config_output = subprocess.check_output([self.oci_net_config, 'configure']).decode('utf-8') + print(config_output) + # self.assertNotIn('ADD', config_output, 'configuration failed') time.sleep(self.waittime) - print(subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8').splitlines()) - unconfig_output = subprocess.check_output([self.oci_net_config, 'unconfigure']).decode('utf-8').splitlines() - print(pformat(unconfig_output, indent=4)) - show_output = subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8') - print(pformat(show_output.splitlines(), indent=4)) - self.assertIn('ADD', show_output, 'un-configuration failed') - print(new_ipv4) - exclude_output = subprocess.check_output([self.oci_net_config, 'configure', '--exclude', new_ipv4]).decode('utf-8').splitlines() - print(pformat(exclude_output, indent=4)) + print(subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8')) + unconfig_output = subprocess.check_output([self.oci_net_config, 'unconfigure']).decode('utf-8') + print(unconfig_output) + # self.assertIn('ADD', unconfig_output, 'un-configuration failed') + print(subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8')) + exclude_output = subprocess.check_output([self.oci_net_config, 'configure', '--exclude', new_ipv4]).decode('utf-8') + print(exclude_output) time.sleep(self.waittime) - show_output = subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8') - print(pformat(show_output.splitlines(), indent=4)) - self.assertIn('EXCL', show_output, 'Exclusion of %s failed' % new_ipv4) - include_output = subprocess.check_output([self.oci_net_config, 'configure', '--include', new_ipv4]).decode('utf-8').splitlines() - print(pformat(include_output, indent=4)) + #self.assertIn('EXCL', exclude_output, 'Exclusion of %s failed' % new_ipv4) + include_output = subprocess.check_output([self.oci_net_config, 'configure', '--include', new_ipv4]).decode('utf-8') + print(include_output) time.sleep(self.waittime) - show_output = subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8') - print(pformat(show_output.splitlines(), indent=4)) - # self.assertNotIn('EXCL', show_output, 'Exclusion of %s failed' % new_ipv4) - delete_data = subprocess.check_output([self.oci_net_config, 'detach-vnic', '--ocid', vn_ocid]).decode('utf-8').splitlines() - print(pformat(delete_data, indent=4)) + print(subprocess.check_output([self.oci_net_config, 'show']).decode('utf-8')) + #self.assertIn('EXCL', include_output, 'Exclusion of %s failed' % new_ipv4) + delete_data = subprocess.check_output([self.oci_net_config, 'detach-vnic', '--ocid', vn_ocid]).decode('utf-8') + print(delete_data) except Exception as e: self.fail('Execution oci-network-config configure has failed: %s' % str(e)) - -if __name__ == '__main__': - suite = unittest.TestLoader().loadTestsFromTestCase(TestCliOciNetworkConfigConfigure) - unittest.TextTestRunner().run(suite) - diff --git a/tests/test_oci_growfs.py b/tests/test_oci_growfs.py index 265c2e29..f26c1295 100644 --- a/tests/test_oci_growfs.py +++ b/tests/test_oci_growfs.py @@ -179,7 +179,7 @@ def test_config_invalid(self): def test_config_non_existent(self): """ - Tests oci notify configuration with a non-existent notification topic. + Tests oci notify configuration with a non existent notification topic. Returns ------- diff --git a/tests/test_oci_volume.py b/tests/test_oci_volume.py index 2783efc5..8a45d4a6 100644 --- a/tests/test_oci_volume.py +++ b/tests/test_oci_volume.py @@ -73,6 +73,7 @@ def tearDown(self): # # attach_volume was removed from instance object # + # GT # this test is obsolete since refactoring, 0.12 def test__oci_instance__attach_volume(self): """ diff --git a/tools/decorators.py b/tools/decorators.py index 626018b6..353ebbbd 100644 --- a/tools/decorators.py +++ b/tools/decorators.py @@ -113,6 +113,8 @@ def skipUnlessOCISDKInstalled(): global __sdk_installed if __sdk_installed is None: try: + # GT not used + # import oci __sdk_installed = True except ImportError: __sdk_installed = False diff --git a/tools/kvm-schema.yaml_save b/tools/kvm-schema.yaml_save deleted file mode 100644 index 91f82041..00000000 --- a/tools/kvm-schema.yaml_save +++ /dev/null @@ -1,288 +0,0 @@ -title: ock-kvm stack input variable schema -description: variable description for oci-kvm stack -informationalText: Variables for creating an oci-kvm stack -schemaVersion: 1.1.0 -version: "20211215" - -# URL of Logo Icon used on Application Information tab. Logo must be 130x130 pixels. -# (Optional) -logoUrl: https://cloudmarketplace.oracle.com/marketplace/content?contentId=53066708 - -# Used in Application Information tab to Hyperlink Title and Logo to the Marketplace -# Listing. -# Also used to link to Listing Usage section for "View Instructions". -# (Optional) If it is missing, Application Information uses the -# "marketplace-listing-id" tag for the same purpose. -# source: -# type: marketplace -# reference: 16132843 - -locale: "en" - -variableGroups: - - title: "Hidden Variable Group" -# visible: false - variables: -# variables used by Terraform but not necesarrily exposed exposed to end user - - tenancy_ocid - - region - - source_type - - current_user_ocid - - - title: "Compute Node" - variables: - - instance_display_name - - compute_compartment_ocid - - - title: "Placement" - variables: - - availability_domain - - - title: "Image and Shape" - variables: - - source_image - - shape - - - title: "Networking" - variables: - - vnic_display_name - - network_compartment_ocid - - subnet_ocid - - assign_public_ipv4 - - private_ipv4 - - dns_record - - hostname - - launch_options - - - title: "Add SSH keys" - variables: - - ssh_public_key - - -variables: - # datetime picker - expireDate: - type: datetime - # hidden - tenancy_ocid: - type: string - title: Tenancy ID - description: The Oracle Cloud Identifier (OCID) for your tenancy - required: true - - region: - type: oci:identity:region:name - title: Region - description: The region in which to create all resources - required: true - - source_type: - type: string - title: source type - default: "image" - description: The type of the source - required: true - - # compute node - instance_display_name: - type: string - title: Instance Name - description: Instance display name - required: true - - compute_compartment_ocid: - type: oci:identity:compartment:id - title: Compartment - description: The compartment OCID - default: compartment_ocid - required: true - - # placement - availability_domain_number: - type: string - required: false - description: Availability Domain Number - - availability_domain: - title: Region Availability Domain - description: The availabiltiy domain in the region. - type: oci:identity:availabilitydomain:name - default: 1 - dependsOn: - compartmentId: compute_compartment_ocid - - # image and shape - source_image: - type: oci:core:image:id - required: true - description: Source Image - dependsOn: - compartmentId: compute_compartment_ocid - - shape: - title: Compute Shape - type: oci:core:instanceshape:name - default: VM.StandardE2.1 - required: true - dependsOn: - compartmentId: compute_compartment_ocid - imageId: source_image - - # networking - network_configuration_strategy: - visible: #($network_strategy == ""Create New VCN and Subnet"") - eq: - - network_strategy - - "Create New VCN and Subnet" - type: enum - title: Configuration Strategy - description: Use recommended configuration or customize it - enum: - - "Use Recommended Configuration" - - "Customize Network Configuration" - required: true - default: "Use Recommended Configuration" - - vcn_display_name: - visible: #($network_strategy == ""Create New VCN and Subnet"") AND (network_configuration_strategy == "Customize Network Configuration") - and: - - eq: - - network_strategy - - "Create New VCN and Subnet" - - eq: - - network_configuration_strategy - - "Customize Network Configuration" - type: string - required: true - title: Name - description: The name of the new Virtual Cloud Network (VCN) - - vcn_id: - visible: #($network_strategy == "Use Existing VCN and Subnet") - eq: - - network_strategy - - "Use Existing VCN and Subnet" - type: oci:core:vcn:id - dependsOn: - compartmentId: network_compartment_ocid - required: true - title: Existing VCN - description: An existing Virtual Cloud Network (VCN) in which to create the compute instances, network resources, and load balancers. If not specified, a new VCN is created. - - vcn_cidr_block: - visible: #($network_strategy == ""Create New VCN and Subnet"") AND (network_configuration_strategy == "Customize Network Configuration") - and: - - eq: - - network_strategy - - "Create New VCN and Subnet" - - eq: - - network_configuration_strategy - - "Customize Network Configuration" - type: string - required: true - pattern: "^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\/(3[0-2]|[1-2]?[0-9])$" - title: CIDR Block - description: The CIDR of the new Virtual Cloud Network (VCN). If you plan to peer this VCN with another VCN, the VCNs must not have overlapping CIDRs. - - vcn_dns_label: - visible: #($network_strategy == ""Create New VCN and Subnet"") AND (network_configuration_strategy == "Customize Network Configuration") - and: - - eq: - - network_strategy - - "Create New VCN and Subnet" - - eq: - - network_configuration_strategy - - "Customize Network Configuration" - type: string - required: true - title: DNS Label - maxLenght: 15 - description: VCN DNS Label. Only letters and numbers, starting with a letter. 15 characters max. - - network_compartment_ocid: - type: oci:identity:compartment:id - required: true - title: Network Compartment - description: The compartment in which to create all Network resources - default: compartment_ocid - - ssh_public_key: - title: SSH Public Key - description: The public SSH key for the key-pair that you want to use, if you wish to login to the instances over SSH - type: oci:core:ssh:publickey - required: true - - - - myVcn: - type: oci:core:vcn:id - dependsOn: - compartmentId: ${vcnCompartment} - visible: - or: - - ${useExistingVcn} - - and: - - and: - - true - - true - - not: - - false - - subnetCompartment: - type: oci:identity:compartment:id - visible: ${useExistingVcn} - - mySubnet: - type: oci:core:subnet:id - dependsOn: - compartmentId: ${subnetCompartment} - vcnId: ${myVcn} - visible: ${useExistingVcn} - - - -outputs: - controlCenterUrl: - type: link - title: Control Center - displayText: Control Center - visible: false - - schemaRegistryUrl: - type: link - title: Schema Registry - displayText: Schema Registry - - schemaRegistryPublicIps: - type: csv - title: Public IPs - - schemaRegistryLoadBalancer: - type: ocid - title: Load Balancer - - brokerPublicIps: - type: csv - - connectUrl: - type: link - title: Connect - displayText: Connect - - connectPublicIps: - type: csv - title: Public IPs - - restUrl: - type: link - title: Rest API - -# primaryOutputButton is a reference to a link output that creates a primary button -# on the Application Information tab. -# (Optional) if not provided, no primary button is shown. Also, if the output -# referenced is not a link output, no button is shown. -primaryOutputButton: ${controlCenterUrl} - -# Used to group Outputs. Any outputs not included in these defined groups, are -# included in a default group labelled "Outputs". -# (Optional) if not groups are given, outputs are not grouped at all. diff --git a/tools/kvm_image/build_image/Makefile b/tools/kvm_image/build_image/Makefile deleted file mode 100644 index 76180ce2..00000000 --- a/tools/kvm_image/build_image/Makefile +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for building kvm image -# -# -INSTALLPACKER=install_packer.py -CONFIGUREIMAGE=configure_image.py -UPLOADIMAGE=upload_image.py -BINARIES=bin/$(INSTALLPACKER) bin/$(CONFIGUREIMAGE) bin/$(UPLOADIMAGE) -TEMPLATES=templates/ol-kvm-image-template.json templates/al-kvm-image-template.json -SCRIPTS=scripts/custom_firstboot.sh scripts/custom_post_install_task.sh scripts/custom_install.sh -MAKEFILE=Makefile -MAKE=$(MAKEFILE) -README=README.md -DOCS=$(README) - -# -TARGET=build-kvm-image -VERSION=0.10_September_13_2022 -OLTYPE=OL -ALTYPE=AL -VALIDTYPES=$(OLTYPE) $(ALTYPE) -REL7=7 -REL8=8 -VALIDRELEASES=$(REL7) $(REL8) -WRITE=@echo -CAT=cat -MKDIR=-mkdir --parents -COPYA=cp --archive -PACKER=/usr/local/bin/packer -#HOMEROOT=$(HOME)/imagebuild -HOMEROOT=$(HOME) -HOMEBINS=$(HOME)/bin -HOMETEMPLATES=$(HOMEROOT)/templates -HOMESCRIPTS=$(HOMEROOT)/scripts -HOMEDOC=$(HOMEROOT)/doc -HOMEMAKE=$(HOMEROOT) -HOMEBIN=$(HOME)/bin -SUDO=sudo -PROFILE=DEFAULT -CREATETAR=tar -cjvf -INSTALL=install --verbose --mode=755 --target=${HOMEBINS} -CONFIG=$(HOME)/.oci/config -DATADIR=$(HOMEROOT)/data -VARFILENAME=image_vars -# -TARBALL=$(TARGET).$(VERSION).bz2 -# -# proxy -# -export no_proxy=169.254.169.254,.oraclecloud.com -# -# help -# -.PHONY: help -help: - $(WRITE) "help info:" - $(WRITE) " make help" - $(WRITE) " make show_version" - $(WRITE) " make install" - $(WRITE) " make install_packer" - $(WRITE) " make configure PROFILE= CONFIG= DATADIR= VARFILENAME= TYPE=[$(OLTYPE)|$(ALTYPE)] RELEASE=[7|8]" - $(WRITE) " TYPE=[$(OLTYPE)|$(ALTYPE)] and RELEASE=[7|8] are mandatory" - $(WRITE) " make configure TYPE=[$(OLTYPE)|$(ALTYPE)] RELEASE=[7|8]" - $(WRITE) " make show_vars" - $(WRITE) " make build_image VARFILENAME= TYPE=[$(OLTYPE)|$(ALTYPE)] RELEASE=[7|8]" - $(WRITE) " make all TYPE=[$(OLTYPE)|$(ALTYPE)] RELEASE=[7|8]" - $(WRITE) " make tarball" - -# -# version info -.PHONY: show_version -show_version: - $(WRITE) "Version of $(TARGET) source is $(VERSION)" -# -# tarball -tarball: - $(CREATETAR) $(TARBALL) ./* -# -# directories -bindir: - $(MKDIR) $(HOME)/bin - -templatedir: - $(MKDIR) $(HOMEROOT)/templates - -scriptdir: - $(MKDIR) $(HOMEROOT)/scripts - -docdir: - $(MKDIR) $(HOMEROOT)/doc - -makedir: - $(MKDIR) $(HOMEROOT) -# -# lists -$(SCRIPTS): scriptdir - $(WRITE) $(SCRIPTS) - -$(TEMPLATES): templatedir - $(WRITE) $(TEMPLATES) - -$(BINARIES): bindir - $(WRITE) $(BINARIES) - -$(DOCS): docdir - $(WRITE) $(DOCS) - -#$(MAKE): makedir -# $(WRITE) $(MAKE) -# -# install -$(HOMESCRIPTS): $(SCRIPTS) - $(COPYA) $^ $@ - -$(HOMETEMPLATES): $(TEMPLATES) - $(COPYA) $^ $@ - -$(HOMEBINS): $(BINARIES) - $(INSTALL) $^ - -$(HOMEDOC): $(DOCS) - $(COPYA) $^ $@ - -$(HOMEMAKE): $(MAKE) - $(COPYA) $^ $@ - -copymakefile: - $(COPYA) $(MAKE) $(HOME) - -install: $(HOMESCRIPTS) $(HOMETEMPLATES) $(HOMEBINS) $(HOMEDOC) copymakefile - $(WRITE) "Installed" -# -# install packer -install_packer: - sudo $(HOMEBIN)/$(INSTALLPACKER) -# -# configure build -profile: - PROFILE=?"DEFAULT" - $(WRITE) "profile: $(PROFILE)" - -config: - CONFIG=?"~/.oci/config" - $(WRITE) "config: $(CONFIG)" - -datadir: - DATADIR=?"~/imagebuild/data" - $(WRITE) "datadir: $(DATADIR)" - -varfile: - VARFILE=?"image_vars" - -type: - @[ "$(TYPE)" ] || ( echo "TYPE [$(OLTYPE)|$(ALTYPE)] is not set"; exit 1 ) - -release: - @[ "$(RELEASE)" ] || ( echo "RELEASE [7|8] is not set"; exit 1 ) - -# configure: install_packer profile config datadir varfile type release -configure: profile config datadir varfile type release - $(WRITE) "$(HOMEBIN)/$(CONFIGUREIMAGE) --profile $(PROFILE) --config $(CONFIG) --data-directory $(DATADIR) --var-file $(VARFILENAME) --type $(TYPE) --release $(RELEASE)" - $(HOMEBIN)/$(CONFIGUREIMAGE) --profile $(PROFILE) --config $(CONFIG) --data-directory $(DATADIR) --var-file $(VARFILENAME) --type $(TYPE) --release $(RELEASE) -# -# show variables file -show_vars: - $(CAT) $(DATADIR)/$(VARFILENAME).tfvars.json -# -# build image -# build_image: VARFILEPATH=$(DATADIR)/$(VARFILENAME).tfvars.json -varfilepath: datadir varfile - VARFILEPATH=$(DATADIR)/$(VARFILENAME).tfvars.json - $(WRITE) "variable file path: $(VARFILEPATH)" - -type_validation: type - VALIDTYPE=$(or $(filter $(TYPE),$(VALIDTYPES)),$(error $$TYPE [$(TYPE)] must be one of $(VALIDTYPES))) - -release_validation: release - VALIDRELEASE=$(or $(filter $(RELEASE),$(VALIDRELEASES)),$(error $$RELEASE [$(RELEASE)] must be one of $(VALIDRELEASES))) - -ifeq ($(TYPE),$(OLTYPE)) -TEMPLATEPATH=$(HOMETEMPLATES)/ol-kvm-image-template.json -else ifeq ($(TYPE),$(ALTYPE)) -TEMPLATEPATH=$(HOMETEMPLATES)/al-kvm-image-template.json -endif - -template: - $(WRITE) $(TEMPLATEPATH) - -build_image: type_validation release_validation varfilepath template - $(WRITE) "no proxy: $${no_proxy}" - $(WRITE) "$(PACKER) build --on-error=ask -var-file=$(DATADIR)/$(VARFILENAME).tfvars.json $(TEMPLATEPATH)" - $(PACKER) build --on-error=ask -var-file=$(DATADIR)/$(VARFILENAME).tfvars.json $(TEMPLATEPATH) - -all: configure build_image - $(WRITE) "build $(TYPE) kvm image." diff --git a/tools/kvm_image/build_image/README.md b/tools/kvm_image/build_image/README.md deleted file mode 100644 index e89278a1..00000000 --- a/tools/kvm_image/build_image/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# Using build_image - -## Introduction - -build_image assists in building KVM images based on Linux images. - -## Prerequisites - -1. The user running the build needs to have direct authenticaton configured. (Instance principal authentication is on the enhancement list.) -2. The build_image uses only private ips. (Public ip is on the enhancement list.) - -## Installation - -The code resides in github. -1. Create a user to be used for the build of the KVM images. This user should have direct authentication via an oci-sdk configuration file set up. Also the user needs to have administration privileges, i.e. being a member of the wheel group. The passwordless sudo is very useful. -2. Connect as this user and create a work-directory. -3. 2 options are available for installation: - 1. Clone the complete git repo and eventually check out a branch: - ```shell - $ git clone - ``` - 2. Pull and expand the tar file **imagebuild.tar** -4. This creates a directory tree in this subdirectory or further down in the git clone **tools** directory: - ```shell - build_image - ├── bin - │   ├── configure_image.py - │   └── install_packer.py - │   └── upload_image.py - │   └── create_imagebuild - ├── Makefile - ├── README.md - ├── scripts - │   ├── custom_firstboot.sh - │   ├── custom_install.sh - │   └── custom_post_install_task.sh - └── templates - ├── al-kvm-image-template.json - └── ol-kvm-image-template.json - - ``` -5. The script **create_imagebuild** can do the most of the above: - 1. Copy the tar file **imagebuild.tar** to a working directory. - 2. Copy the **sdk config** and **PEM RSA private key** files to a working directory. - 3. Copy the tar ball to a working directory. - 4. Run **create_imagebuild** as root - ```shell - # ./imagebuild/build_image/bin/create_imagebuild - 23-Sep-2021 13:42:00 --- ERR --- username, userid, config, key file and/or tar file missing - - Usage: - - ./imagebuild/build_image/bin/create_imagebuild - - : the userid for the user. - : the sdk config file. - : the sdk key file. - : the tar file with the tool. - - Creates a user with name imagebuild and userid - with groupid 1000 and in group wheel with home - directory /home/imagebuild; configures the oci-sdk for direct authentication. - ``` - Execution: - ```shell - # ./imagebuild/build_image/bin/create_imagebuild 2000 /tmp/config /tmp/oci_private_key.pem /tmp/imagebuild.tar.bz2 - 03-May-2022 09:36:06 --- MSG --- Username is imagebuild - 03-May-2022 09:36:06 --- MSG --- UserID is 2000 - 03-May-2022 09:36:06 --- MSG --- SDK config file is /tmp/config - 03-May-2022 09:36:06 --- MSG --- Key file /tmp/oci_private_key.pem - 03-May-2022 09:36:06 --- MSG --- TAR file /tmp/imagebuild.tar.bz2 - 03-May-2022 09:36:06 --- MSG --- user home directory is /home/imagebuild - 03-May-2022 09:36:06 --- MSG --- .oci is /home/imagebuild/.oci - 03-May-2022 09:36:06 --- MSG --- config file is /home/imagebuild/.oci/config - 03-May-2022 09:36:06 --- MSG --- sdk key file is /home/imagebuild/.oci/oci_api_key.pem - 03-May-2022 09:36:07 --- MSG --- imagebuild created successfully. - Changing password for user imagebuild. - New password: - Retype new password: - passwd: all authentication tokens updated successfully. - 03-May-2022 09:36:19 --- MSG --- Password for imagebuild set successfully. - 03-May-2022 09:36:19 --- MSG --- Created bin successfully. - 03-May-2022 09:36:19 --- MSG --- Created tests successfully. - 03-May-2022 09:36:19 --- MSG --- Created work successfully. - 03-May-2022 09:36:19 --- MSG --- Created scripts successfully. - 03-May-2022 09:36:19 --- MSG --- Created templates successfully. - 03-May-2022 09:36:19 --- MSG --- /home/imagebuild/.oci created successfully. - 03-May-2022 09:36:19 --- MSG --- /home/imagebuild/.oci permission set to 700 successfully. - 03-May-2022 09:36:19 --- MSG --- Copied /tmp/config to /home/imagebuild/.oci/config successfully. - 03-May-2022 09:36:19 --- MSG --- /home/imagebuild/.oci/config permissions set to 600 successfully. - 03-May-2022 09:36:19 --- MSG --- Copied /tmp/oci_private_key.pem to /home/imagebuild/.oci/oci_api_key.pem successfully. - 03-May-2022 09:36:19 --- MSG --- - ./bin/ - ./bin/configure_image.py - ./bin/create_imagebuild - ./bin/install_packer.py - ./bin/upload_image.py - ./imagebuild.tar.bz2 - ./Makefile - ./README.md - ./scripts/ - ./scripts/custom_firstboot.sh - ./scripts/custom_install.sh - ./scripts/custom_post_install_task.sh - ./templates/ - ./templates/al-kvm-image-template.json - ./templates/ol-kvm-image-template.json - 03-May-2022 09:36:19 --- MSG --- /tmp/imagebuild.tar.bz2 successfully expanded - 03-May-2022 09:36:19 --- MSG --- Copied configure_image.py in place successfully - 03-May-2022 09:36:19 --- MSG --- Copied create_imagebuild in place successfully - 03-May-2022 09:36:19 --- MSG --- Copied install_packer.py in place successfully - 03-May-2022 09:36:19 --- MSG --- Copied upload_image.py in place successfully - 03-May-2022 09:36:19 --- MSG --- Copied custom_firstboot.sh in place successfully - 03-May-2022 09:36:19 --- MSG --- Copied custom_install.sh in place successfully - 03-May-2022 09:36:19 --- MSG --- Copied custom_post_install_task.sh in place successfully - 03-May-2022 09:36:20 --- MSG --- Copied al-kvm-image-template.json in place successfully - 03-May-2022 09:36:20 --- MSG --- Copied ol-kvm-image-template.json in place successfully - 03-May-2022 09:36:20 --- MSG --- Copied Makefile in place successfully - 03-May-2022 09:36:20 --- MSG --- Copied README.md in place successfully - 03-May-2022 09:36:20 --- MSG --- Removed work/bin successfully - 03-May-2022 09:36:20 --- MSG --- Removed work/scripts successfully - 03-May-2022 09:36:20 --- MSG --- Removed work/templates successfully - 03-May-2022 09:36:20 --- MSG --- Completed successfully - ``` -7. Another option to install this package, e.g. if user imagebuild already exists, expand the tar ball, go to the root of the expanded tree and run as the user which is going to do the image build (**imagebuild** if the script is used) : - ``` - $ make install - ``` -8. The files copied and/or created: - * **Makefile**: make commands. - * **README.md**: this readme file. - * **ol-kvm-image-template.json**: packer template file. - * **al-kvm-image-template.json**: packer template file. - * **custom_post_install_task.sh**: bash script run during image creation. - * **custom_install.sh** bash script installing additional packages - * **custom_firstboot.sh**: bash script run during image creation. - * **install_packer.py**: installs the latest version of **packer** in **/usr/local/bin** - * **configure_image.py**: collects all the data required for building the image. - * **upload_image.py**: uploads an image to an object storage. - * **create_imagebuild**: creates the imagebuild user. - -## Usage - -Go to the **$HOME** directory. -```shell -$ make -help info: - make help - make show_version - make install - make install_packer - make configure PROFILE= CONFIG= DATADIR= VARFILENAME= TYPE=[OL|AL] RELEASE=[7|8] - The paramaters TYPE=[$(OLTYPE)|$(ALTYPE)] and RELEASE=[7|8] are mandatory - make configure TYPE=[OL|AL] - make show_vars - make build_image VARFILENAME= TYPE=[OL|AL] - make all TYPE=[OL|AL] RELEASE=[7|8] -``` - -The **Makefile** contains all what is necessary to build an Oracle Linux based KVM image. For example, to create an OL7 KVM image run: -```shell -$ make configure TYPE=OL RELEASE=7 -$ make buildimage TYPE=OL RELEASE=7 -``` -or in one go: -```shell -$ make all TYPE=OL RELEASE=7 -``` -* **make configure** installs the latest version of **packer** and generates the json parameter file for the packer scripts. -* **make buildimage** creates the actual image; running this separately is useful if one or a few parameter(s) in the json paramter file are changed manually. -* When specifying the **VARFILENAME** for the **buildimage** option, the extension **.tfvar.json** is added implicitly. -* The built image is placed in the **custom images** repository. The image name contains the date of creation. - diff --git a/tools/kvm_image/build_image/bin/configure_image.py b/tools/kvm_image/build_image/bin/configure_image.py deleted file mode 100755 index 99447eb5..00000000 --- a/tools/kvm_image/build_image/bin/configure_image.py +++ /dev/null @@ -1,883 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -import argparse -import errno -import getpass -import glob -import json -import logging -import os -import re -import sys -import termios -import tty -from datetime import date -from datetime import datetime -from subprocess import call - -import oci - -# -# locale -lc_all = 'en_US.UTF8' -# -# logfile -default_log = '/tmp/configure_image_%s.log' % datetime.now().strftime('%Y%m%d_%H%M') -# -# custom scripts -custom_kvm_build_scripts = ['custom_install.sh', 'custom_firstboot.sh', 'custom_post_install_task.sh'] - -_logger = logging.getLogger(__name__) - - -def print_g(msg, term=True, destination=default_log): - """ - Write msg to stdout and to file. - - Parameters - ---------- - msg: str - The text. - term: bool - If true, write to stdout. - destination: str - Path of destination file. - - Returns - ------- - No return value. - """ - if term: - print('%s' % msg) - with open(destination, 'a') as f: - f.write('%s\n' % msg) - f.flush() - - -def parse_args(): - """ - Parse the command line arguments. - -p | --profile - -c | --config - -d | --data-directory - -f | --var-file - -t | --type [OL|AL] - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(description='Configure Oracle Linux KVM image build.') - parser.add_argument('-p', '--profile', - action='store', - dest='profile', - default='DEFAULT', - help='The profile in the cli/sdk config file, default is DEFAULT.') - parser.add_argument('-c', '--config', - action='store', - dest='configfile', - default='~/.oci/config', - help='The cli/sdk config file, default is ~/.oci/config.') - parser.add_argument('-d', '--data-directory', - action='store', - dest='datadir', - default='~/imagebuild/data', - help='Root directory with data for the image build, default is ~/imagebuild/data.') - parser.add_argument('-f', '--var-file', - action='store', - dest='varfilename', - default='image_vars', - help='Filename to store the variables; the extension .tfvars.json is added automatically.') - parser.add_argument('-t', '--type', - action='store', - choices=['OL', 'AL'], - dest='oltype', - help='Build Oracle Linux or Autonomous Linux, mandatory.', - required=True) - parser.add_argument('-r', '--release', - action='store', - choices=['7', '8'], - dest='olrelease', - help='Build OL7 or OL8 release, mandatory.', - required=True) - parser._optionals.title = 'Arguments' - args = parser.parse_args() - return args - - -def _clear_term(): - """ - Clears the terminal window. - - Returns - ------- - No return value. - """ - _ = call('clear' if os.name == 'posix' else 'cls') - return True - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def _is_int(string_data): - """ - Verifies if string is a valid int. - - Parameters - ---------- - string_data: str - The string to be evaluated. - - Returns - ------- - bool: True on success, false otherwise. - """ - return re.match(r"[-+]?\d+$", string_data) is not None - - -def _get_current_user(): - """ - Get the current username. - - Returns - ------- - str: the username. - """ - return getpass.getuser() - - -def _get_current_user_home(): - """ - Get the home directory of the current user. - - Returns - ------- - str: the full path of the home directory. - """ - return os.path.expanduser('~') - - -def _from_stdin(prompt, default=None): - """ - Read from stdin, if default is not set to None, some input is expected. - - Parameters - ---------- - prompt: str - The stdin prompt. - default: - Default value. - - Returns - ------- - value read - """ - while True: - return_val = input('%-40s: ' % prompt) - if bool(return_val): - return return_val - if default is not None: - return default - - -def get_configdata(profile, configfile='~/.oci/config'): - """ - Read the oci sdk/cli config file. - - Parameters - ---------- - profile: str - the config profile. - configfile: str - the path of the configfile. - Returns - ------- - code: int 0 for success, 1 for failure - dict: the config data. - """ - sdkconfigfile = configfile - if configfile.startswith('~/'): - sdkconfigfile = os.path.expanduser('~') + configfile[1:] - if os.path.exists(sdkconfigfile): - try: - return 0, oci.config.from_file(file_location=sdkconfigfile, profile_name=profile) - except Exception as e: - exit_msg = str(e) - else: - exit_msg = '%s does not exist' % sdkconfigfile - return 1, exit_msg - - -def _select_from(some_list, prompt, default_val=0): - """ - Select an item from a list. - - Parameters - ---------- - some_list: list - list of items. - prompt: str - prompt - default_val: int - default index value if no input. - - Returns - ------- - The list element. - """ - while 1 == 1: - selected_nb = input("%s ==> " % prompt) - if not bool(selected_nb): - selected_nb = str(default_val) - if _is_int(selected_nb): - select_index = int(selected_nb) - if 0 <= select_index < len(some_list): - break - print_g('Index %d out of range.' % select_index) - else: - print_g('Invalid input: %s' % selected_nb) - _logger.debug('Selected %s', some_list[select_index]) - return some_list[select_index] - - -def this_path(this_file=None): - """ - Root of the operation. - - Parameters - ---------- - this_file: str - Filename, default is this script location. - - Returns - ------- - str: path - """ - exec_dir = os.path.dirname(os.path.realpath(sys.argv[0] or 'whocares')) - return exec_dir if not this_file else os.path.join(exec_dir, this_file) - - -def _get_today(): - """ - Get todays date as a sting in YYYY.MM.DD format - - Returns - ------- - str: today in requested format. - - """ - return date.today().strftime("%Y.%m.%d") - - -def _get_timestamp(): - """ - Get timestamp as a string in YYYYMMDD-HHMISS format. - - Returns - ------- - str: timestamp in requested format. - """ - return datetime.now().strftime('%Y%m%d-%H%M%S') - - -def select_compartment_id(config_dict, prompt): - """ - Select a compartment in the tenancy. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - - prompt: str - The prompt - Returns - ------- - str: the compartment ocid. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_compartments = oci.pagination.list_call_get_all_results(oci_identity.list_compartments, config_dict['tenancy']) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for comp in oci_compartments.data: - print_g('%4d %-30s %s' % (oci_compartments.data.index(comp), comp.name, comp.id)) - compartment_data = _select_from(oci_compartments.data, prompt) - print_g(compartment_data, term=False) - print_g(msg='Selected compartment:\n%30s: %s' % (compartment_data.name, compartment_data.id)) - return compartment_data.id - - -def select_availability_domain_name(config_dict, compartment_id, prompt): - """ - Select an availability domain. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - prompt: str - The prompt - - Returns - ------- - str: the availability domain name - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_availabitly_domains = oci.pagination.list_call_get_all_results(oci_identity.list_availability_domains, compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for domain in oci_availabitly_domains.data: - print_g('%4d %-30s %s' % (oci_availabitly_domains.data.index(domain), domain.name, domain.id)) - availability_domain = _select_from(oci_availabitly_domains.data, prompt) - print_g(availability_domain, term=False) - print_g('Selected availability domain: \n%30s' % availability_domain.name) - return availability_domain.name - - -def select_image_id(config_dict, compartment_id, prompt): - """ - Select an image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - prompt: str - The prompt - - Returns - ------- - str: the image ocid - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - # oci_images = oci_imageclient.list_images(compartment_id, operating_system='Oracle Linux') - # oci_images = oci_imageclient.list_images(compartment_id, limit=500) - oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, compartment_id, operating_system='Zero').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, compartment_id, operating_system='Custom').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, compartment_id, operating_system='Oracle Linux').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, compartment_id, operating_system='Oracle Autonomous Linux').data - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for image in oci_images_data: - # print_g('%4d %-30s %s' % (oci_images.data.index(image), image.display_name, image.id)) - # print_g('%4d %-30s %s %s' % (oci_images.data.index(image), image.display_name, image.operating_system, image.id)) - print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.operating_system)) - image_data = _select_from(oci_images_data, prompt) - print_g(image_data, term=False) - print_g('Selected image: \n%30s: %s' % (image_data.display_name, image_data.id)) - return image_data.id - - -def select_vcn_id(config_dict, compartment_id, prompt): - """ - Select a VCN. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - prompt: str - The prompt - - Returns - ------- - str: the VCN ocid - """ - try: - oci_vncclient = oci.core.VirtualNetworkClient(config_dict) - oci_vcns = oci.pagination.list_call_get_all_results(oci_vncclient.list_vcns, compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for vcn in oci_vcns.data: - print_g('%4d %-30s %s' % (oci_vcns.data.index(vcn), vcn.display_name, vcn.id)) - vcn = _select_from(oci_vcns.data, prompt) - print_g(vcn, term=False) - print_g('Selected VCN: \n%30s: %s' % (vcn.display_name, vcn.id)) - return vcn.id - - -def select_subnet_id(config_dict, compartment_id, vcn_id, prompt): - """ - Select a subnet. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - vcn_id: str - The VCN ocid - prompt: str - The prompt - - Returns - ------- - str: the subnet ocid - """ - try: - oci_subnetclient = oci.core.VirtualNetworkClient(config_dict) - oci_subnets = oci.pagination.list_call_get_all_results(oci_subnetclient.list_subnets, compartment_id, vcn_id=vcn_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for subnet in oci_subnets.data: - print_g('%4d %-30s %s' % (oci_subnets.data.index(subnet), subnet.display_name, subnet.id)) - subnet = _select_from(oci_subnets.data, prompt) - print_g(subnet, term=False) - print_g('Selected subnet: \n%30s: %s' % (subnet.display_name, subnet.id)) - return subnet.id - - -def select_shape(config_dict, image_ocid, prompt): - """ - Select a compatible shape for the image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - image_ocid: str - The ocid of the image. - prompt: str - The prompt. - - Returns - ------- - str: The shape - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - oci_shapes = oci.pagination.list_call_get_all_results(oci_imageclient.list_image_shape_compatibility_entries, image_ocid) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - while 1 == 1: - for shape_dict in oci_shapes.data: - print_g('%4d %-30s' % (oci_shapes.data.index(shape_dict), shape_dict.shape)) - shape = _select_from(oci_shapes.data, prompt) - # - # is shape Flex? - if bool(re.search('Flex', shape.shape)): - print_g('*** Flex shapes are not supported here.') - _ = sys.stdout.write('Press Key to continue.') - sys.stdout.flush() - _ = _getch().rstrip() - else: - break - - print_g(shape, term=False) - print_g('Selected shape: \n%30s' % shape.shape) - return shape.shape - - -def get_image_name_prefix(): - """ - Get the image name prefix. - - Returns - ------- - str: the prefix. - """ - while 1 == 1: - try: - image_prefix = input('Provide image name prefix:> ').strip() - if len(image_prefix) > 0: - return image_prefix - except Exception as e: - _logger.debug('Failed to read image name prefix, retry.') - - -def get_OL_version(): - """ - Get the Oracle Linux version from prompt. - - Returns - ------- - str: the version. - """ - while 1 == 1: - try: - ol_version = input('Provide Oracle Linux version used:> ').strip() - if len(ol_version) > 0: - return ol_version - except Exception as e: - _logger.debug('Failed to read Oracle Linux version.') - - -def collect_build_parameters(config_data): - """ - Callect the data from oci required by packer to build the image. - - Parameters - ---------- - config_data: dict - The oci configuration file data. - Returns - ------- - dict: the data. - """ - # - # initialise data structure - image_data = dict() - # - # Compartment ocid - print_g('Instance Compartment.\n') - image_data['user_compartment_ocid'] \ - = select_compartment_id(config_data, 'Select instance compartment.') - _clear_term() - # - # Network compartment ocid - print_g('Network Compartment.\n') - image_data['user_network_compartment_ocid'] \ - = select_compartment_id(config_data, - 'Select network compartment.') - _clear_term() - # - # Virtual cloud network ocid - print_g('Virtual Cloud Network.\n') - image_data['user_vcn_ocid'] \ - = select_vcn_id(config_data, - image_data['user_network_compartment_ocid'], - 'Select virtual cloud network.') - _clear_term() - # - # Subnet ocid - print_g('Subnet.\n') - image_data['user_subnet_ocid'] \ - = select_subnet_id(config_data, - image_data['user_network_compartment_ocid'], - image_data['user_vcn_ocid'], 'Select subnet.') - _clear_term() - # - # Image ocid - print_g('Image.\n') - image_data['user_base_image_ocid'] \ - = select_image_id(config_data, - image_data['user_compartment_ocid'], - 'Select image.') - _clear_term() - # - # Availability domain - print_g('Availabiltiy Domain.\n') - image_data['user_availability_domain'] \ - = select_availability_domain_name(config_data, - image_data['user_compartment_ocid'], - 'Select availability domain.') - _clear_term() - # - # Shape - print_g('Shape.\n') - image_data['user_shape_name'] \ - = select_shape(config_data, image_data['user_base_image_ocid'], 'Select shape') - _clear_term() - # - # OL version - print_g('OL version.\n') - image_data['user_OL_version'] = get_OL_version() - _clear_term() - - return image_data - - -def collect_instance_parameters(image_data, ol_type, ol_release): - """ - Callect the data from the operator required by packer to build the image. - - Parameters - ---------- - image_data: dict - The current data. - ol_type: str - [OL | AL] - ol_release: str - [7 | 8] - Returns - ------- - dict: the updated data. - """ - # - # date strings - today_date_str = _get_today() - # print_g(msg='Today string: %s' % today_date_str) - today_timestamp = _get_timestamp() - # print_g(msg='Timestamp: %s' % today_timestamp) - # - # flavor - image_data['user_flavor'] = 'Autonomous' if ol_type == 'AL' else 'NonAutonomous' - print_g(msg='Flavor: %s' % image_data['user_flavor']) - # - # image name - release_part = '-07-KVM-' + today_date_str if ol_release == '7' else '-08-KVM-' + today_date_str - image_data['user_image_name'] = 'AL' + release_part if ol_type == 'AL' else 'OL' + release_part - print_g(msg='Image name: %s' % image_data['user_image_name']) - # - # instance name - release_part = '-07-KVM-builder' + today_timestamp if ol_release == '7' else '-08-KVM-builder' + today_timestamp - image_data['user_instance_name'] = 'AL' + release_part if ol_type == 'AL' else 'OL' + release_part - print_g(msg='Instance name: %s' % image_data['user_instance_name']) - - return image_data - - -def build_data(image_data, dir_root): - """ - Add data necessary for the build. - Parameters - ---------- - image_data: dict - The current data. - dir_root: str - The root dir to start looking for the custom scripts. - Returns - ------- - dict: the updated data. - """ - # - # look in directory tree for the custom_*sh scripts - cs_path = None - for custom_script in custom_kvm_build_scripts: - cs_path = glob.glob(dir_root + '/**/%s' % custom_script, recursive=True) - if bool(cs_path): - print_g(msg='script %s' % cs_path) - script_name = os.path.basename(custom_script) - script_base = os.path.splitext(script_name)[0] - image_data['user_' + script_base] = script_name - image_data['user_' + script_base + '_path'] = cs_path[0] - cs_path = None - return image_data - - -def show_parameters(data): - """ - Show collected data. - - Parameters - ---------- - data: dict - The data. - - Returns - ------- - No return value. - """ - _clear_term() - print('Data collected to build an image:\n') - for k, v in data.items(): - print('%40s: %s' % (k, v)) - print('\n') - - -def main(): - """ - Configure auto tests. - - Returns - ------- - int: 0 on success, raises exception on failure. - """ - logging.basicConfig(filename='/tmp/oci_utils_configure_image.log', level=logging.DEBUG) - # - # parse the commandline - args = parse_args() - # - # init log - try: - with open(default_log, 'w') as f: - f.write('') - f.flush() - print_g(msg='Log file %s initialised.' % default_log, term=True) - except Exception as e: - _logger.error('Failed to initialise log file %s: %s', default_log, str(e)) - sys.exit(1) - # - # current user - operator = _get_current_user() - operator_home = _get_current_user_home() - _clear_term() - print_g(msg='%30s: %s\n%30s: %s' % ('Username', operator, 'Home', operator_home), term=True) - # - # date strings - # today_date_str = _get_today() - # print_g(msg='Today string: %s' % today_date_str) - # today_timestamp = _get_timestamp() - # print_g(msg='Timestamp: %s' % today_timestamp) - # - # parse the commandline - args = parse_args() - # - # get configuration data - ret, configuration = get_configdata(args.profile, args.configfile) - if ret == 1: - _logger.error('Failed to read config file %s', args.configfile) - print_g('*** ERROR *** %s' % configuration) - sys.exit(1) - - print_g(msg='Configuration', term=True) - for k, v in configuration.items(): - print_g(msg='%30s: %s' % (k, v), term=True) - # - # continue? - resp = _read_yn(prompt='Continue?', yn=True, default_yn=True) - if not resp: - sys.exit('Exiting.') - else: - _clear_term() - # - # data from oci - image_data = collect_build_parameters(configuration) - # - # data from operator - image_data = collect_instance_parameters(image_data, args.oltype, args.olrelease) - # - # data for build - image_data = build_data(image_data, operator_home) - # - # packer var file, create dir if not exits. - data_dir = operator_home + '/imagebuild_data' if args.datadir.startswith('~') else args.datadir - # tfvarsfile = data_dir + '/' + args.varfilename + '_' + image_data['user_image_name'] + '.tfvars.json' - tfvarsfile = data_dir + '/' + args.varfilename + '.tfvars.json' - try: - os.makedirs(os.path.dirname(tfvarsfile)) - except OSError as e: - if e.errno != errno.EEXIST: - sys.exit('Failed to create directory %s: %s' % (os.path.dirname(tfvarsfile), str(e))) - print_g(msg='%30s: %s' % ('Packer var file', tfvarsfile), term=True) - # - # validate - show_parameters(image_data) - resp = _read_yn('Proceed with this data?') - if not resp: - sys.exit('Data not saved, terminating.') - print('Saving data in %s' % tfvarsfile) - # - # save data - try: - with open(tfvarsfile, 'w') as tfvj: - json.dump(image_data, tfvj, indent=4) - return 0 - except Exception as e: - raise Exception('Failed to write %s:' % tfvarsfile) from e - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/kvm_image/build_image/bin/create_imagebuild b/tools/kvm_image/build_image/bin/create_imagebuild deleted file mode 100755 index 0d52bf88..00000000 --- a/tools/kvm_image/build_image/bin/create_imagebuild +++ /dev/null @@ -1,203 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -# -# creates the imagebuild user -# - - -USERNAME=imagebuild -EXPECTEDNBPAR=4 -USERADD=$(command -v useradd) -GETENT=$(command -v getent) -PASSWD=$(command -v passwd) -SU=$(command -v su) -SED=$(command -v sed) -COPY=$(command -v cp) -MOVE=$(command -v mv) -CAT=$(command -v cat) -CHDIR="cd" -MKDIR=$(command -v mkdir) -DELETE="$(command -v rm) -rf" -CHMOD=$(command -v chmod) -CHOWN=$(command -v chown) -TAR="$(command -v tar) -jxvf" -RMDIR="$(command -v rm) -rf" -GROUPID=1000 -USERSHELL="/bin/bash" -BINDIR="bin" -TESTDIR="tests" -WORKDIR="work" -SCRIPTDIR="scripts" -TEMPLATEDIR="templates" -DIRLIST=( "${BINDIR}" "${TESTDIR}" "${WORKDIR}" "${SCRIPTDIR}" "${TEMPLATEDIR}") -BINFILES=( "configure_image.py" "create_imagebuild" "install_packer.py" "upload_image.py") -SCRIPTFILES=( "custom_firstboot.sh" "custom_install.sh" "custom_post_install_task.sh") -TEMPLATEFILES=( "al-kvm-image-template.json" "ol-kvm-image-template.json") -TOCLEANUP=( "${WORKDIR}/${BINDIR}" "${WORKDIR}/${SCRIPTDIR}" "${WORKDIR}/${TEMPLATEDIR}") -OTHERFILES=( "Makefile" "README.md") -KEYFILENAME="oci_api_key.pem" -# -# http(s) proxy -HTTPPROXY="http://www-proxy-hqdc.us.oracle.com:80" -HTTPSPROXY="http://www-proxy-hqdc.us.oracle.com:80" - -Usage() { - echo "" - echo "Usage:" - echo "" - echo "${0} " - echo "" - echo " : the userid for the user." - echo " : the sdk config file." - echo " : the sdk key file." - echo " : the tar file with the tool." - echo "" - echo " Creates a user with name imagebuild and userid " - echo " with groupid 1000 and in group wheel with home" - echo " directory /home/imagebuild; configures the oci-sdk for direct authentication." - echo "" -} - -MessageStd() { - local MSGNOW=$(date '+%d-%b-%Y %H:%M:%S') - echo "${MSGNOW} --- MSG --- ${1}" -} - -MessageErrBase() { - local MSGNOW=$(date '+%d-%b-%Y %H:%M:%S') - echo "${MSGNOW} --- ERR --- ${1}" -} - -MessageErrFatal() { - RETVAL="${1}" - MSG="${2}" - if [ "${RETVAL}" -ne 0 ]; then - MessageErrBase "${MSG}: ${RETVAL}" - exit 1 - fi -} - -ExitOnError() { - RETV="${1}" - ERRORMESSAGE="${2}" - SUCCESSMESSAGE="${3}" - MessageErrFatal "${RETV}" "${ERRORMESSAGE}" - MessageStd "${SUCCESSMESSAGE}" -} - -NBPAR="${#}" -if [ ${NBPAR} -ne ${EXPECTEDNBPAR} ]; then - MessageErrBase "username, userid, config, key file and/or tar file missing" - Usage - exit 1 -fi - -USERID=${1} -SDKCONFIG=${2} -KEYFILE=${3} -TARFILE=${4} -MessageStd "Username is ${USERNAME}" -MessageStd "UserID is ${USERID}" -MessageStd "SDK config file is ${SDKCONFIG}" -MessageStd "Key file ${KEYFILE}" -MessageStd "TAR file ${TARFILE}" -# -HOMEDIR="/home/${USERNAME}" -MessageStd "user home directory is ${HOMEDIR}" -HOMEOCI="${HOMEDIR}/.oci" -MessageStd ".oci is ${HOMEOCI}" -HOMEOCICONFIG="${HOMEOCI}/config" -MessageStd "config file is ${HOMEOCICONFIG}" -HOMESDKKEY="${HOMEOCI}/${KEYFILENAME}" -MessageStd "sdk key file is ${HOMESDKKEY}" -#MASTERMAKE=${HOMEGITDIR}/tests/automation/Makefile -#MessageStd "Makefile location is ${MASTERMAKE}" -# -# -${GETENT} passwd "${USERNAME}" > /dev/null 2>&1 -RETVAL=${?} -if [ ${RETVAL} -eq 0 ]; then - MessageErrFatal "${USERNAME} already exists" -fi -# -# add user -${USERADD} -c "user ${USERNAME}" -d "${HOMEDIR}" -g ${GROUPID} -G wheel -m -s "${USERSHELL}" -u "${USERID}" "${USERNAME}" -ExitOnError "${?}" "Failed to create user ${USERNAME}" "${USERNAME} created successfully." -${PASSWD} "${USERNAME}" -ExitOnError "${?}" "Failed to set password for ${USERNAME}" "Password for ${USERNAME} set successfully." -# -# create automation directories -for thisdir in "${DIRLIST[@]}" -do - ${SU} -l "${USERNAME}" -c "${MKDIR} -p ${thisdir}" - ExitOnError ${?} "Failed to create ${thisdir}" "Created ${thisdir} successfully." -done -# -# create oci sdk config directory -${SU} -l "${USERNAME}" -c "${MKDIR} ${HOMEOCI}" -ExitOnError "${?}" "Failed to create ${HOMEOCI}" "${HOMEOCI} created successfully." -# -# copy oci sdk config in place. -${SU} -l "${USERNAME}" -c "${CHMOD} 700 ${HOMEOCI}" -${SU} -l "${USERNAME}" -c "${CHMOD} 700 ${HOMEOCI}" -ExitOnError "${?}" "Failed to ${CHMOD} 700 ${HOMEOCI}" "${HOMEOCI} permission set to 700 successfully." -# -# copy sdk config file -${SU} -l "${USERNAME}" -c "${COPY} ${SDKCONFIG} ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to ${COPY} ${SDKCONFIG} to ${HOMEOCICONFIG}" "Copied ${SDKCONFIG} to ${HOMEOCICONFIG} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMEOCICONFIG}" "${HOMEOCICONFIG} permissions set to 600 successfully." -# -# copy and update key file -${SU} -l "${USERNAME}" -c "${COPY} ${KEYFILE} ${HOMESDKKEY}" -ExitOnError "${?}" "Failed to ${COPY} ${KEYFILE} to ${HOMESDKKEY}" "Copied ${KEYFILE} to ${HOMESDKKEY} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMESDKKEY}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMESDKKEY}" -RETVAL="${?}" -MessageErrFatal ${RETVAL} "Failed to ${CHMOD} 600 ${HOMESDKKEY}" "${SED} -i /key_file/c\"key_file=${HOMESDKKEY}\" ${HOMEOCICONFIG}" -${SU} -l "${USERNAME}" -c "${SED} -i /key_file/c\"key_file=${HOMESDKKEY}\" ${HOMEOCICONFIG}" -# -# expand tar file -${SU} -l "${USERNAME}" -c "${CHDIR} ${WORKDIR}; ${TAR} ${TARFILE}" -ExitOnError "${?}" "Failed to expand ${TARFILE}" "${TARFILE} successfully expanded" -# -# copy bin in place -for binfile in "${BINFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKDIR}/bin/${binfile} ${HOMEDIR}/bin" - ExitOnError ${?} "Failed to copy ${binfile} in place." "Copied ${binfile} in place successfully" -done -# -# copy scripts in place -for scriptfile in "${SCRIPTFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKDIR}/scripts/${scriptfile} ${HOMEDIR}/scripts" - ExitOnError ${?} "Failed to copy ${scriptfile} in place." "Copied ${scriptfile} in place successfully" -done -# -# copy templates in place -for templatefile in "${TEMPLATEFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKDIR}/templates/${templatefile} ${HOMEDIR}/templates" - ExitOnError ${?} "Failed to copy ${templatefile} in place." "Copied ${templatefile} in place successfully" -done -# -# copy Makefile and README.md -for otherfile in "${OTHERFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKDIR}/${otherfile} ${HOMEDIR}" - ExitOnError ${?} "Failed to copy ${otherfile} in place." "Copied ${otherfile} in place successfully" -done -# -# cleanup -for tocleanupfile in "${TOCLEANUP[@]}" -do - ${SU} -l "${USERNAME}" -c "${RMDIR} ${HOMEDIR}/${tocleanupfile}" - ExitOnError ${?} "Failed to remove ${HOMEDIR}/${tocleanupfile}." "Removed ${HOMEDIR}/${tocleanupfile} successfully" -done -# -# done -MessageStd "Completed successfully" diff --git a/tools/kvm_image/build_image/bin/install_packer.py b/tools/kvm_image/build_image/bin/install_packer.py deleted file mode 100755 index 446b7b61..00000000 --- a/tools/kvm_image/build_image/bin/install_packer.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -""" -Installs the latest version of the Packer software, download it from the Hashicorp website. -""" -import os -from zipfile import ZipFile -import sys -from urllib.request import urlopen -import urllib.request -import subprocess -from html.parser import HTMLParser - -url_base = 'https://releases.hashicorp.com/packer' -packer_exec = '/usr/local/bin/packer' -os.environ['http_proxy'] = 'http://www-proxy.us.oracle.com:80' -os.environ['https_proxy'] = 'http://www-proxy.us.oracle.com:80' - -version = '0.9.0' - -class MyHTMLParser(HTMLParser): - """ - Parse webpage. - """ - lsVersions = list() - - def handle_starttag(self, startTag, attrs): - if startTag == 'a': - for name, value in attrs: - if name == 'href': - if 'packer' in value: - self.lsVersions.append(value) - - -def get_most_recent_packer_version(url): - """ - Find the latest Packer version. - - Parameters - ---------- - url: str - The Hashicorp website. - - Returns - ------- - str: the most recent packer version. - """ - parser = MyHTMLParser() - packer_base = urlopen(url_base) - parser.feed(str(packer_base.read())) - packer_version_list = parser.lsVersions - pure_version_list = list() - for ver in packer_version_list: - pure_version_list.append(ver.split('/')[2]) - version_dict = dict() - for ver in pure_version_list: - ver_nb = 0 - for ver_x in ver.split('.'): - ver_nb = ver_nb*100 + int(ver_x) - version_dict[ver_nb] = ver - return '%s' % sorted(version_dict.items(), reverse=True)[0][1] - - -def download_file(url, destination): - """ - Download a file using an url. - - Parameters - ---------- - url: str - The file locator. - destination: str - Full path of destination. - - Returns - ------- - bool: True on success, False on failure. - """ - try: - with urllib.request.urlopen(url) as response, open(destination, 'wb') as out_file: - data = response.read() - out_file.write(data) - return True - except Exception as e: - print('Failed to download %s: %s' % (url, str(e))) - return False - - -def unzip_file(zipped_file): - """ - Unzip a zipfile in /tmp. - - Parameters - ---------- - zipped_file: str - Zipped file name. - - Returns - ------- - bool: True on success, False on failure. - """ - try: - zipfile = ZipFile(zipped_file, 'r') - zipfile.extractall('/tmp') - zipfile.close() - return True - except Exception as e: - print('Failed to unzip %s; %s' % (zipped_file, str(e))) - return False - - -def remove_file(somepath): - """ - Delete the packer executable from /usr/local/bin. - - Parameters - ---------- - somepepath: str - File path to be removed. - - Returns - ------- - bool: True on success, False on failure. - """ - remove_cmd = ['sudo', 'rm', '-rf', somepath] - try: - if os.path.exists(packer_exec): - proc = subprocess.Popen(remove_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - else: - print('%s does not exists.' % packer_exec) - return True - except Exception as e: - print('Failed to remove %s; %s' % (packer_exec, str(e))) - return False - - -def install_usrlocalbin(from_path, exec_file): - """ - Install a file in /usr/local/bin. - - Parameters - ---------- - from_path: str - Source directory. - exec_file: str - File name. - - Returns - ------- - bool: True on succes, False on failure. - """ - install_cmd = ['sudo', '-S', 'install', '-m', '755', '%s/%s' % (from_path, exec_file), '/usr/local/bin'] - try: - proc = subprocess.Popen(install_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - return True - except Exception as e: - print('Failed to install %s: %s' % (exec_file, str(e))) - return False - - -def main(): - """ - Install most recent version of Packer software. - - Returns - ------- - int: 0 on success, 1 on failure. - """ - print('Running %s version %s' % (sys.argv[0], version)) - packer_version = get_most_recent_packer_version(url_base) - print('Most recent version of Packer: %s' % packer_version) - packer_zip = 'packer_%s_linux_amd64.zip' % packer_version - packer_url = url_base + '/%s/%s' % (packer_version,packer_zip) - print('URL for Packer distro: %s' % packer_url) - if download_file(packer_url, packer_zip): - print('Successfully downloaded: %s' % packer_url) - else: - print('Failed to download %s' % packer_url) - sys.exit(1) - if unzip_file(packer_zip): - print('Sucessfully unzipped %s' % packer_zip) - else: - print('Failed to unzip %s' % packer_zip) - sys.exit(1) - if remove_file(packer_exec): - print('Successfully removed %s' % packer_exec) - else: - print('Failed to remove %s' % packer_exec) - sys.exit(1) - if install_usrlocalbin('/tmp', 'packer'): - print('Successfully installed %s' % packer_exec) - else: - print('Failed to install %s' % packer_exec) - sys.exit(1) - if remove_file(packer_zip): - print('Successfully removed %s' % packer_zip) - else: - print('Failed to remove %s' % packer_zip) - sys.exit(0) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/kvm_image/build_image/bin/upload_image.py b/tools/kvm_image/build_image/bin/upload_image.py deleted file mode 100755 index 3d89a8bd..00000000 --- a/tools/kvm_image/build_image/bin/upload_image.py +++ /dev/null @@ -1,465 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Upload an (image) file to object storage. -""" -import argparse -import logging -import os -import sys -import termios -import threading -import time -import tty -from datetime import datetime - -import oci - -# logging.basicConfig(level=logging.DEBUG, filename='/tmp/upload_image.log', filemode='w', format='%(asctime)s - %(name)s - %(level)s : %(message)s', datefmt='%d-%b-%y %H:%M:%S') -_logger = logging.getLogger(__name__) - -def parse_args(): - """ - Parse the command line arguments and return an object representing the - command line as returned by the argparse's parse-args(). - arguments: - -i|--image-name ; mandatory. - -b|--bucket-name ; mandatory. - -o|--output-name ; optional - -y|--yes suppose the answer YES to all Y/N questions - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(description='Utility to upload a file to object storage of ' - 'the Oracle Cloud Infrastructure.') - # - parser.add_argument('-p', '--profile', - action='store', - dest='profile', - type=str, - default='DEFAULT', - help='The profile from the config file, the default is DEFAULT.') - parser.add_argument('-c', '--config-file', - action='store', - dest='config_file', - type=argparse.FileType('r'), - default='~/.oci/config', - help='The oci config file, the default = ~/.oci/config.') - parser.add_argument('-f', '--file-name', - action='store', - dest='file_name', - type=argparse.FileType('r'), - required=True, - help='The file name to be uploaded.') - parser.add_argument('-b', '--bucket-name', - action='store', - dest='bucket_name', - required=True, - help='The name of the object storage.') - parser.add_argument('-o', '--output-name', - action='store', - dest='output_name', - help='The name the image will be stored in the object storage.') - parser.add_argument('--yes', '-y', - action='store_true', - dest='yes_flag', - default=False, - help='Answer YES to all y/n questions.') - parser._optionals.title = 'Arguments' - args = parser.parse_args() - if args.output_name is None: - args.output_name = args.image_name - return args - - -def terminal_dimension(): - """ - Collect the dimension of the terminal window. - - Returns - ------- - tuple: (nb rows, nb colums) - """ - try: - terminal_size = os.get_terminal_size() - return terminal_size.lines, terminal_size.columns - except Exception as e: - # - # fail to get terminal dimension, because not connected to terminal? - # returning dummy - print(' Failed to determine terminal dimensions: %s; falling back to 80x80'% str(e)) - return 80, 80 - - -class ProgressBar(threading.Thread): - """ - Class to generate an indication of progress, does not actually - measure real progress, just shows the process is not hanging. - """ - _default_progress_chars = ['#'] - - def __init__(self, bar_length, progress_interval, progress_chars=None): - """ - Progressbar initialisation. - - Parameters: - ---------- - bar_length: int - Length of the progress bar. - progress_interval: float - Interval in sec of change. - progress_chars: list - List of char or str to use; the list is mirrored before use. - """ - self._stopthread = threading.Event() - threading.Thread.__init__(self) - # - # length of variable progress bar - self._bar_len = bar_length - 14 - # - # progress interval in sec - self._prog_int = progress_interval - if progress_chars is None: - self._prog_chars = self._default_progress_chars - else: - self._prog_chars = progress_chars - # - # nb progress symbols - self._nb_prog_chars = len(self._prog_chars) - # - # the max len of the progress symbols, should be all equal - self._prog_len = 0 - for s in self._prog_chars: - ls = len(s) - if ls > self._prog_len: - self._prog_len = ls - # - # nb iterations per bar - self._cntr = self._bar_len - self._prog_len + 1 - self.stop_the_progress_bar = False - - def run(self): - """ - Execute the progress bar. - - Returns - ------- - No return value. - """ - # - # counter in progress bar symbols - i = 0 - j = i % self._nb_prog_chars - # - # counter in bar - k = 0 - sys.stdout.write('\n') - sys.stdout.flush() - start_time = datetime.now() - while True: - now_time = datetime.now() - delta_time = now_time - start_time - hrs, rest = divmod(delta_time.seconds, 3600) - mins, secs = divmod(rest, 60) - pbar = ' ' \ - + '%02d:%02d:%02d' % (hrs, mins, secs) \ - + ' [' \ - + ' '*k \ - + self._prog_chars[j] \ - + ' ' * (self._bar_len - k - self._prog_len) \ - + ']' - sys.stdout.write('\r%s' % pbar) - sys.stdout.flush() - k += 1 - if k == self._cntr: - k = 0 - i += 1 - j = i % self._nb_prog_chars - time.sleep(self._prog_int) - if self.stop_the_progress_bar: - now_time = datetime.now() - delta_time = now_time - start_time - hrs, rest = divmod(delta_time.seconds, 3600) - mins, secs = divmod(rest, 60) - pbar = ' ' \ - + '%02d:%02d:%02d' % (hrs, mins, secs) \ - + ' [ ' \ - + ' %s' % self._prog_chars[j] \ - + ' done ]' \ - + (self._bar_len - self._prog_len - 5)*' ' - sys.stdout.write('\r%s\n' % pbar) - sys.stdout.flush() - break - - def stop(self): - """ - Notify thread to stop the progress bar. - - Returns - ------- - No return value. - """ - self.stop_the_progress_bar = True - self.join() - sys.stdout.write('\n') - sys.stdout.flush() - - def join(self, timeout=None): - """ - Terminate the thread. - - Parameters - ---------- - timeout: float - Time to wait if set. - - Returns - ------- - No return value. - """ - self._stopthread.set() - threading.Thread.join(self, timeout) - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def read_yn(prompt, yn=True, waitenter=False, suppose_yes=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - yn_prompt += ' (y/N) ' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn = list(resp)[0] - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn = _getch() - - sys.stdout.write('\n') - return bool(yn.upper() == 'Y') - - -def get_oci_config(configfile, profile): - """ - Read the oci-sdk configuration data from file. - - configfile: str - The oci config file. - profile: str - The oci profile. - - Returns - ------- - dict: The configuration on success, None otherwise. - """ - try: - config = oci.config.from_file(file_location=configfile, profile_name=profile) - return config - except oci.exceptions.ProfileNotFound as notfound: - print(' OCI configuration file %s not found.', configfile) - except oci.exceptions.ConfigFileNotFound as notfound: - print(' OCI profile %s not found.', profile) - except Exception as e: - print(' Failed to load oci configuration data: %s' % str(e)) - return None - - -def bucket_exists(bucket_name, config): - """ - Verify if the object storage exists. - - Parameters - ---------- - bucket_name: str - The object storage name. - config: dict - The oci-sdk configuration. - - Returns - ------- - bool: True on success, False on failure. - """ - try: - object_storage_client = oci.object_storage.ObjectStorageClient(config) - namespace = object_storage_client.get_namespace().data - bucket_data = object_storage_client.get_bucket(namespace_name=namespace, bucket_name=bucket_name) - print(' Bucket %s exists in namespace %s.' % (bucket_data.data.name, bucket_data.data.namespace)) - return True - except Exception as e: - if hasattr(e, 'message'): - print(' Failed to locate bucket %s: %s' % (bucket_name, e.message)) - else: - print(' Failed to locate bucket %s' % bucket_name) - return False - - -def object_exists(object_name, bucket_name, config): - """ - Verify if object is present in the object storage. - - Parameters - ---------- - object_name: str - The object name. - bucket_name: str - The bucket name. - config: dict - The oci-sdk configuration. - - Returns - ------- - bool: True on success, False on failure. - """ - try: - object_storage_client = oci.object_storage.ObjectStorageClient(config) - namespace = object_storage_client.get_namespace().data - object_list_data = object_storage_client.list_objects(namespace_name=namespace, bucket_name=bucket_name) - except Exception as e: - print(' Failed to get contents of %s: %s' % (bucket_name, str(e))) - return False - for obj in object_list_data.data.objects: - if obj.name == object_name: - print(' %s is already present in %s.' % (object_name, bucket_name)) - return False - print(' %s is not yet present in %s.' % (object_name, bucket_name)) - return True - - -def upload_object(object_name, output_name, bucket_name, config): - """ - Upload object to bucket as output. - - Parameters - ---------- - object_name: str - The path of the object to upload. - output_name: str - The name the object is stored in the object storage. - bucket_name: str - The name of the object storage. - config: dict - The oci-sdk configuration. - - Returns - ------- - bool: True on success, False on failure. - """ - try: - object_storage_client = oci.object_storage.ObjectStorageClient(config) - namespace_name = object_storage_client.get_namespace().data - upload_manager = oci.object_storage.UploadManager(object_storage_client=object_storage_client, allow_parallel_uploads=True, parallel_process_count=10) - response = upload_manager.upload_file(namespace_name=namespace_name, bucket_name=bucket_name, file_path=object_name, object_name=output_name) - print(' Successfully uploaded %s to %s: %s' % (object_name, bucket_name, response.data)) - return True - except Exception as e: - print(' Failed to upload %s to %s: %s' % (object_name, bucket_name, str(e))) - _logger.error('%s' % str(e), stack_info=True, exc_info=True) - return False - - -def main(): - """ - Main - - Returns - ------- - int: 0 on success, 1 on failure. - """ - os.environ['LC_ALL'] = 'en_US.UTF8' - args = parse_args() - # - sdk_config = get_oci_config(args.config_file, args.profile) - if sdk_config is None: - sys.exit(1) - # - file_path = args.file_name.name - if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)): - print(' %s does not exists or os not readable.' % file_path) - sys.exit(1) - # - bucket_name = args.bucket_name - if not bucket_exists(bucket_name, sdk_config): - sys.exit(1) - # - if args.output_name: - output_name = args.output_name - else: - output_name = os.path.splitext(os.path.basename(file_path))[0] - # - yes_flag = args.yes_flag - # - if not object_exists(output_name, bucket_name, sdk_config): - sys.exit(1) - # - if not read_yn('\n Agree to proceed uploading %s to %s as %s?' % (file_path, bucket_name, output_name), - waitenter=True, - suppose_yes=yes_flag): - sys.exit('\n Exiting.') - # - try: - _, nb_columns = terminal_dimension() - upload_progress = ProgressBar(nb_columns, 0.2, progress_chars=['uploading %s' % output_name]) - upload_progress.start() - if upload_object(file_path, output_name, bucket_name, sdk_config): - pass - upload_progress.stop() - except Exception as e: - print(' Upload failed: %s' % str(e)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/kvm_image/build_image/scripts/custom_firstboot.sh b/tools/kvm_image/build_image/scripts/custom_firstboot.sh deleted file mode 100644 index 861441c0..00000000 --- a/tools/kvm_image/build_image/scripts/custom_firstboot.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# Add the libvirt group to the opc user to allow easier virsh usage -sudo usermod -aG libvirt opc -echo 'export LIBVIRT_DEFAULT_URI="qemu:///system"' >> /home/opc/.bashrc \ No newline at end of file diff --git a/tools/kvm_image/build_image/scripts/custom_install.sh b/tools/kvm_image/build_image/scripts/custom_install.sh deleted file mode 100644 index 225b2e36..00000000 --- a/tools/kvm_image/build_image/scripts/custom_install.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - -CMDPATH="command -v" -SUDO=$($CMDPATH sudo) -DNF=$($CMDPATH dnf) -YUM=$($CMDPATH yum) -# -# if dnf exists, this is OL8 or later, use dnf. -if [ ! ${DNF} ] -then - # - # OL7 - ${SUDO} "${YUM}" install --assumeyes python36-libvirt - ${SUDO} "${YUM}" install --assumeyes git -else - # - # OL8+ - ${SUDO} "${DNF}" install --assumeyes python3-libvirt - ${SUDO} "${DNF}" install --assumeyes git -fi \ No newline at end of file diff --git a/tools/kvm_image/build_image/scripts/custom_post_install_task.sh b/tools/kvm_image/build_image/scripts/custom_post_install_task.sh deleted file mode 100644 index 7366b233..00000000 --- a/tools/kvm_image/build_image/scripts/custom_post_install_task.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - -CMDPATH="command -v" -SUDO=$($CMDPATH sudo) -AWK=$($CMDPATH awk) -SED=$($CMDPATH sed) -DNF=$($CMDPATH dnf) -YUM=$($CMDPATH yum) -YUMCONFIGMANAGER=$($CMDPATH yum-config-manager) -COPY="cp" -WRITE="echo" -NOW=$(date +"%Y%m%d_%H%M") -# -# if dnf exists, this is OL8 or later, use dnf. -if [ ! "${DNF}" ] -then - # - # OL7 - # Enable KVM channel - ${YUMCONFIGMANAGER} --enable ol7_kvm_utils - # - # Install oci-utils-kvm, qemu, libvirt, and virt-install packages - ${YUM} --assumeyes install oci-utils-kvm \ - qemu-kvm \ - qemu-img \ - libvirt \ - libvirt-python \ - libvirt-client \ - virt-install \ - virt-viewer - ${YUM} --assumeyes install redhat-lsb-core - -else - # - # OL8+ - # Install oci-utils-kvm, qemu, libvirt, and virt-install packages - ${DNF} --assumeyes install oci-utils-kvm \ - qemu-kvm \ - qemu-img \ - libvirt \ - python3-libvirt \ - libvirt-client \ - virt-install \ - virt-viewer \ - @virt - ${DNF} --assumeyes install redhat-lsb-core - # - # Install UEKR7 kernel on OL8 - LSBRELEASE=$($CMDPATH lsb_release) - OSREL=$(${LSBRELEASE} -rs | ${AWK} -F'.' '{print $1}') -# -# To force UEK7 kernel installed. -# if [ "${OSREL}" == '8' ] -# then -# ${DNF} --enablerepo=ol8_UEKR7 --assumeyes update kernel-uek kernel-uek-devel -# fi - # UEKR7 is default on OL9, which is not yet supported. -fi -# -# Disable lvm devices -${SUDO} ${COPY} /etc/lvm/lvm.conf /etc/lvm/lvm.conf."${NOW}" -${SUDO} "${SED}" -i '/# global_filter =/a\\tglobal_filter = [ "a|^/dev/sda.*$|", "r|/dev/sd*|" ]' /etc/lvm/lvm.conf -# -# Preparing the KVM Server for virtualization -# Backup Grub File -${SUDO} ${COPY} /etc/default/grub /etc/default/grub."${NOW}" -# -# Edit grub and include the following options -GRUB_FILE=/etc/default/grub -GRUB_STRING="intel_iommu=on amd_iommu=on" -${SUDO} "${SED}" -i "/^GRUB_CMDLINE_LINUX=/s/\"$/ ${GRUB_STRING}\"/" ${GRUB_FILE} -# -# Enable nested virt -# Intel -${WRITE} 'options kvm-intel nested=Y'|${SUDO} tee /etc/modprobe.d/kvm_intel.conf >/dev/null -# AMD -${WRITE} 'options kvm-amd nested=1'|${SUDO} tee /etc/modprobe.d/kvm_amd.conf >/dev/null -# -# Enable tuned -${SUDO} systemctl enable tuned -${SUDO} systemctl start tuned -${SUDO} tuned-adm profile virtual-host -# -# Recreate grub to validate all the changes -${SUDO} ${COPY} /boot/efi/EFI/redhat/grub.cfg /boot/efi/EFI/redhat/grub.cfg."${NOW}" -${SUDO} grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg -# -# Allow the opc user to use virsh without the need for sudo -${SUDO} ${COPY} /etc/libvirt/libvirtd.conf /etc/libvirt/libvirtd.conf."${NOW}" -${SUDO} "${SED}" -i\ - -e 's/^#unix_sock_group .*/unix_sock_group = "libvirt"/'\ - -e 's/^#unix_sock_ro_perms .*/unix_sock_ro_perms = "0770"/'\ - -e 's/^#unix_sock_rw_perms .*/unix_sock_rw_perms = "0770"/'\ - /etc/libvirt/libvirtd.conf -${SUDO} "${SED}" -i\ - -e 's,^#uri_default \(.*\),uri_default \1,'\ - /etc/libvirt/libvirt.conf -# -# Enable ocid service -${SUDO} systemctl enable ocid.service diff --git a/tools/kvm_image/build_image/templates/al-kvm-image-template.json b/tools/kvm_image/build_image/templates/al-kvm-image-template.json deleted file mode 100644 index cd0188f1..00000000 --- a/tools/kvm_image/build_image/templates/al-kvm-image-template.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "variables": { - "user_availability_domain": "", - "user_base_image_ocid": "", - "user_compartment_ocid": "", - "user_subnet_ocid": "", - "user_image_name": "", - "user_instance_name": "", - "user_OL_version": "", - "user_OL_flavour": "Autonomous", - "user_shape_name": "", - "user_custom_post_install_task": "", - "user_custom_firstboot": "" - }, - "builders": [ - { - "use_instance_principals": "false", - "ssh_username": "opc", - "use_private_ip": "true", - "availability_domain": "{{user `user_availability_domain`}}", - "base_image_ocid": "{{user `user_base_image_ocid`}}", - "compartment_ocid": "{{user `user_compartment_ocid`}}", - "shape": "{{user `user_shape_name`}}", - "subnet_ocid": "{{user `user_subnet_ocid`}}", - "image_name": "{{user `user_image_name`}}", - "instance_name": "{{user `user_instance_name`}}", - "tags": { - "OL_flavour": "{{user `user_OL_flavour`}}", - "OL_version": "{{user `user_OL_version`}}" - }, - "type": "oracle-oci" - } - ], - "provisioners": [ - { - "type": "file", - "source": "{{user `user_custom_post_install_task_path`}}", - "destination": "/tmp/{{user `user_custom_post_install_task`}}" - }, - { - "type": "file", - "source": "{{user `user_custom_firstboot_path`}}", - "destination": "/tmp/{{user `user_custom_firstboot`}}" - }, - { - "type": "file", - "source": "{{user `user_custom_install_path`}}", - "destination": "/tmp/{{user `user_custom_install`}}" - }, - { - "type": "shell", - "inline": [ - "sudo -u root /bin/bash /tmp/custom_install.sh", - "sudo -u root /bin/bash /tmp/custom_post_install_task.sh", - "sudo -u root /bin/bash /tmp/custom_firstboot.sh" - ] - }, - { - "type": "shell", - "inline": [ - "sudo rm -f /etc/cron.d/al-update /var/lib/al-config/* /var/log/al.log", - "sudo rm -f /tmp/custom*sh", - "sudo sed -i '/^auto_update_time_window=/d;/# Auto update time window/d' /etc/al-config/al.conf", - "sudo cp /var/lib/cloud/scripts/per-instance/oci.sh /var/tmp", - "sudo /usr/libexec/oci-image-cleanup --force", - "sudo mv /var/tmp/oci.sh /var/lib/cloud/scripts/per-instance", - "history -c" - ] - } - ] -} diff --git a/tools/kvm_image/build_image/templates/ol-kvm-image-template.json b/tools/kvm_image/build_image/templates/ol-kvm-image-template.json deleted file mode 100644 index 9dd91d3e..00000000 --- a/tools/kvm_image/build_image/templates/ol-kvm-image-template.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "variables": { - "user_availability_domain": "", - "user_base_image_ocid": "", - "user_compartment_ocid": "", - "user_subnet_ocid": "", - "user_image_name": "", - "user_instance_name": "", - "user_OL_version": "", - "user_OL_flavour": "NonAutonomous", - "user_shape_name": "", - "user_custom_post_install_task": "", - "user_custom_firstboot": "" - }, - "builders": [ - { - "use_instance_principals": "false", - "ssh_username": "opc", - "use_private_ip": "true", - "availability_domain": "{{user `user_availability_domain`}}", - "base_image_ocid": "{{user `user_base_image_ocid`}}", - "compartment_ocid": "{{user `user_compartment_ocid`}}", - "shape": "{{user `user_shape_name`}}", - "subnet_ocid": "{{user `user_subnet_ocid`}}", - "image_name": "{{user `user_image_name`}}", - "instance_name": "{{user `user_instance_name`}}", - "tags": { - "OL_flavour": "{{user `user_OL_flavour`}}", - "OL_version": "{{user `user_OL_version`}}" - }, - "type": "oracle-oci" - } - ], - "provisioners": [ - { - "type": "file", - "source": "{{user `user_custom_post_install_task_path`}}", - "destination": "/tmp/{{user `user_custom_post_install_task`}}" - }, - { - "type": "file", - "source": "{{user `user_custom_firstboot_path`}}", - "destination": "/tmp/{{user `user_custom_firstboot`}}" - }, - { - "type": "file", - "source": "{{user `user_custom_install_path`}}", - "destination": "/tmp/{{user `user_custom_install`}}" - }, - { - "type": "shell", - "inline": [ - "sudo -u root /bin/bash /tmp/custom_install.sh", - "sudo -u root /bin/bash /tmp/custom_post_install_task.sh", - "sudo -u root /bin/bash /tmp/custom_firstboot.sh" - ] - }, - { - "type": "shell", - "inline": [ - "sudo rm -f /tmp/custom*sh", - "history -c" - ] - } - ] -} diff --git a/tools/kvm_image/test_image/Makefile b/tools/kvm_image/test_image/Makefile deleted file mode 100644 index b89fd9fc..00000000 --- a/tools/kvm_image/test_image/Makefile +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for creating an instance in OCI -# -# -# -# proxy -# -export no_proxy=169.254.169.254,.oraclecloud.com -# -HOSTLOCATION=host_instance -GUESTLOCATON=guest_instance - -TERRAFORM4OCIPY=create_kvm_host.py -TERRAFORM4OCI=create_kvm_host -CREATEKVMHOSTUSER=create_kvmhost_user -CREATETESTVMPY=create_guest_vm.py -CREATETESTVM=create_guest_vm - -BINARIES=bin/$(CREATEKVMHOSTUSER) - -HOSTBINARIES=$(HOSTLOCATION)/bin/$(TERRAFORM4OCI) $(HOSTLOCATION)/bin/$(TERRAFORM4OCIPY) - -CREATEGUESTVM=$(GUESTLOCATON)/bin/$(CREATETESTVM) -CREATEGUESTVMPY=$(GUESTLOCATON)/bin/$(CREATETESTVMPY) -GUESTBINARIES=$(CREATEGUESTVM) $(CREATEGUESTVMPY) - -BASEDATATF=$(HOSTLOCATION)/base_instance/data.tf -BASEMAINTF=$(HOSTLOCATION)/base_instance/main.tf -BASEOUTPUTTF=$(HOSTLOCATION)/base_instance/output.tf -BASES=$(BASEDATATF) $(BASEMAINTF) $(BASEOUTPUTTF) - -TFAPITF=$(HOSTLOCATION)/tf_scripts/api_key.tf -TFRSATF=$(HOSTLOCATION)/tf_scripts/rsa_key.tf -TFRSATFPUB=$(HOSTLOCATION)/tf_scripts/rsa_pub_key.tf -TFDATATF=$(HOSTLOCATION)/tf_scripts/data.tf -TFMAINTF=$(HOSTLOCATION)/tf_scripts/main.tf -TFVERSION=$(HOSTLOCATION)/tf_scripts/version.tf -TFOUTPUTTF=$(HOSTLOCATION)/tf_scripts/output.tf -TFSCRIPTS=$(TFAPITF) $(TFDATATF) $(TFMAINTF) $(TFVERSION) $(TFOUTPUTTF) $(TFRSATF) $(TFRSATFPUB) - -GUESTKICKSTARTBRIDGEOL7=$(GUESTLOCATON)/templates/kickstart_bridge_template_ol7 -GUESTKICKSTARTBRIDGEOL8=$(GUESTLOCATON)/templates/kickstart_bridge_template_ol8 -GUESTKICKSTARTBRIDGEOL9=$(GUESTLOCATON)/templates/kickstart_bridge_template_ol9 - -GUESTKICKSTARTDIRECTOL7=$(GUESTLOCATON)/templates/kickstart_direct_template_ol7 -GUESTKICKSTARTDIRECTOL8=$(GUESTLOCATON)/templates/kickstart_direct_template_ol8 -GUESTKICKSTARTDIRECTOL9=$(GUESTLOCATON)/templates/kickstart_direct_template_ol9 -GUESTTEMPLATES=$(GUESTKICKSTARTBRIDGEOL7) $(GUESTKICKSTARTBRIDGEOL8) $(GUESTKICKSTARTBRIDGEOL9) $(GUESTKICKSTARTDIRECTOL7) $(GUESTKICKSTARTDIRECTOL8) $(GUESTKICKSTARTDIRECTOL9) - -INITIALSCRIPT=$(HOSTLOCATION)/sh_scripts/initial_config.sh -SHSCRIPTS=$(INITIALSCRIPT) -# -# files involved -FILELIST=Makefile README.md $(HOSTBINARIES) $(GUESTBINARIES) $(BASES) $(TFSCRIPTS) $(SHSCRIPTS) $(GUESTTEMPLATES) $(BINARIES) -# -TARGET=create_kvm_instance -VERSION=0.11_May_05_2022 -WRITE=@echo -CREATETAR=tar -cjvf -EXPANDTAR=tar -xjvf -MKDIR=-mkdir -p -RMFORCE=rm -rf -DELETE=rm -f -INSTALL=install --mode=755 -COPYA=cp -a -SUDO=sudo -LINK=ln -s -# -# destinations -HOMEBINS=$(HOME)/bin -HOMETEMPLATES=$(HOME)/templates -HOMEBASES=$(HOME)/$(TARGET)/base_instance -HOMETFSCRIPTS=$(HOME)/$(TARGET)/tf_scripts -HOMESHSCRIPTS=$(HOME)/$(TARGET)/sh_scripts -# -# tarball name -TARBALL=$(TARGET).$(VERSION).bz2 -# help -# -.PHONY: help -help: - $(WRITE) "help info:" - $(WRITE) " make help" - $(WRITE) " make show_version" - $(WRITE) " make tarball" - $(WRITE) " make installhost" - $(WRITE) " make installguest" - $(WRITE) " make uninstallguest" - $(WRITE) " make uninstallhost" - -# -# version info -.PHONY: showversion -show_version: - $(WRITE) "version of $(TARGET) source is $(VERSION)" -# -# create tarball -tarball: - $(CREATETAR) $(TARBALL) $(FILELIST) -# -# create directories -bindir: - $(MKDIR) $(HOMEBINS) - -basedir: - $(MKDIR) $(HOMEBASES) - -tfscriptdir: - $(MKDIR) $(HOMETFSCRIPTS) - -shscriptdir: - $(MKDIR) $(HOMESHSCRIPTS) - -templatedir: - $(MKDIR) $(HOMETEMPLATES) -# -# lists -$(GUESTBINARIES): bindir - $(WRITE) $(GUESTBINARIES) - -$(BASES): basedir - $(WRITE) $(BASES) - -$(TFSCRIPTS): tfscriptdir - $(WRITE) $(TFSCRIPTS) - -$(SHSCRIPTS): shscriptdir - $(WRITE) $(SHSCRIPTS) - -$(GUESTTEMPLATES): templatedir - $(WRITE) $(TEMPLATES) -# -# -# install guest -guestbin: $(GUESTBINARIES) - $(INSTALL) $^ $(HOMEBINS) - -$(HOMEBASES): $(BASES) - $(COPYA) $^ $@ - -$(HOMETFSCRIPTS): $(TFSCRIPTS) - $(COPYA) $^ $@ - -$(HOMESHSCRIPTS): $(SHSCRIPTS) - $(COPYA) $^ $@ - -$(HOMETEMPLATES): $(GUESTTEMPLATES) - $(COPYA) $^ $@ - -installguest: guestbin $(HOMETEMPLATES) - $(WRITE) "Installed Create Guest VM" -# -# uninstall guest -uninstallguest: - $(RMFORCE) $(HOME)/$(TARGET) - $(DELETE) $(HOME)/$(GUESTBINARIES) - $(WRITE) "Uninstalled" -# -# install host -installhost: \ No newline at end of file diff --git a/tools/kvm_image/test_image/README.md b/tools/kvm_image/test_image/README.md deleted file mode 100644 index b937a749..00000000 --- a/tools/kvm_image/test_image/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# Assistance for creating a kvm host instance and kvm guests in OCI. - -## Prerequisites - -- terraform software installed -- oci-sdk installed and configured for direct authentication (for now) - - -## Initialisation -- copy this tree or the tar ball (and expand) to a working directory. -- chdir to **kvm** directory - -## Install host code -- As user with root privileges, run **create_kvmhost_user** which creates the user kvmhost and copies the necessary files in place. - - ```shell - $ tar xvf /tmp/create_instance.0.10_May_02_2022.bz - Makefile - README.md - host_instance/bin/create_kvm_host - host_instance/bin/create_kvm_host.py - guest_instance/bin/create_guest_vm - guest_instance/bin/create_guest_vm.py - host_instance/base_instance/data.tf - host_instance/base_instance/main.tf - host_instance/base_instance/output.tf - host_instance/tf_scripts/api_key.tf - host_instance/tf_scripts/data.tf - host_instance/tf_scripts/main.tf - host_instance/tf_scripts/version.tf - host_instance/tf_scripts/output.tf - host_instance/scripts/initial_config.sh - guest_instance/templates/kickstart_bridge_template_ol7 - guest_instance/templates/kickstart_bridge_template_ol8 - guest_instance/templates/kickstart_direct_template_ol7 - guest_instance/templates/kickstart_direct_template_ol8 - create_kvmhost_user - - $ sudo ./create_kvmhost_user 3000 /tmp/config /tmp/oci_private_key.pem /tmp/create_instance.0.10_May_02_2022.bz - 03-May-2022 16:46:54 --- MSG --- Username is kvmhost - 03-May-2022 16:46:54 --- MSG --- UserID is 3000 - 03-May-2022 16:46:54 --- MSG --- SDK config file is /tmp/config - 03-May-2022 16:46:54 --- MSG --- Key file /tmp/oci_private_key.pem - 03-May-2022 16:46:54 --- MSG --- TAR file /tmp/create_instance.0.10_May_02_2022.bz - 03-May-2022 16:46:54 --- MSG --- user home directory is /home/kvmhost - 03-May-2022 16:46:54 --- MSG --- .oci is /home/kvmhost/.oci - 03-May-2022 16:46:54 --- MSG --- config file is /home/kvmhost/.oci/config - 03-May-2022 16:46:54 --- MSG --- sdk key file is /home/kvmhost/.oci/oci_api_key.pem - 03-May-2022 16:46:55 --- MSG --- kvmhost created successfully. - Changing password for user kvmhost. - New password: - Retype new password: - passwd: all authentication tokens updated successfully. - 03-May-2022 16:47:06 --- MSG --- Password for kvmhost set successfully. - 03-May-2022 16:47:06 --- MSG --- Created bin successfully. - 03-May-2022 16:47:06 --- MSG --- Created base_instance successfully. - 03-May-2022 16:47:06 --- MSG --- Created work successfully. - 03-May-2022 16:47:06 --- MSG --- Created scripts successfully. - 03-May-2022 16:47:06 --- MSG --- Created tf_scripts successfully. - 03-May-2022 16:47:06 --- MSG --- /home/kvmhost/.oci created successfully. - 03-May-2022 16:47:06 --- MSG --- /home/kvmhost/.oci permission set to 700 successfully. - 03-May-2022 16:47:06 --- MSG --- Copied /tmp/config to /home/kvmhost/.oci/config successfully. - 03-May-2022 16:47:06 --- MSG --- /home/kvmhost/.oci/config permissions set to 600 successfully. - 03-May-2022 16:47:06 --- MSG --- Copied /tmp/oci_private_key.pem to /home/kvmhost/.oci/oci_api_key.pem successfully. - 03-May-2022 16:47:06 --- MSG --- - Makefile - README.md - host_instance/bin/create_kvm_host - host_instance/bin/create_kvm_host.py - guest_instance/bin/create_guest_vm - guest_instance/bin/create_guest_vm.py - host_instance/base_instance/data.tf - host_instance/base_instance/main.tf - host_instance/base_instance/output.tf - host_instance/tf_scripts/api_key.tf - host_instance/tf_scripts/data.tf - host_instance/tf_scripts/main.tf - host_instance/tf_scripts/version.tf - host_instance/tf_scripts/output.tf - host_instance/scripts/initial_config.sh - guest_instance/templates/kickstart_bridge_template_ol7 - guest_instance/templates/kickstart_bridge_template_ol8 - guest_instance/templates/kickstart_direct_template_ol7 - guest_instance/templates/kickstart_direct_template_ol8 - create_kvmhost_user - 03-May-2022 16:47:06 --- MSG --- /tmp/create_instance.0.10_May_02_2022.bz successfully expanded - 03-May-2022 16:47:06 --- MSG --- Copied create_kvm_host.py in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied create_kvm_host in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied initial_config.sh in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied data.tf in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied main.tf in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied output.tf in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied api_key.tf in place successfully - 03-May-2022 16:47:06 --- MSG --- Copied data.tf in place successfully - 03-May-2022 16:47:07 --- MSG --- Copied main.tf in place successfully - 03-May-2022 16:47:07 --- MSG --- Copied output.tf in place successfully - 03-May-2022 16:47:07 --- MSG --- Copied version.tf in place successfully - 03-May-2022 16:47:07 --- MSG --- Copied Makefile in place successfully - 03-May-2022 16:47:07 --- MSG --- Copied README.md in place successfully - 03-May-2022 16:47:07 --- MSG --- Completed successfully - ``` - -- install by executing `make install`, this will the template structure to a directory `~/create_instance` and the executable `create_instance` to `~/bin` -- run `~/bin/create_instance` which completes the variable data, creates a directory `~/oci_instance/` which contains the data for creating the instance, and creates create and destroy scripts. - -## Install guest code \ No newline at end of file diff --git a/tools/kvm_image/test_image/bin/create_kvmhost_user b/tools/kvm_image/test_image/bin/create_kvmhost_user deleted file mode 100755 index 81fb5afc..00000000 --- a/tools/kvm_image/test_image/bin/create_kvmhost_user +++ /dev/null @@ -1,245 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. -# -# creates the kvmhost user -# - - -USERNAME=kvmhost -EXPECTEDNBPAR=6 -USERADD=$(command -v useradd) -GETENT=$(command -v getent) -PASSWD=$(command -v passwd) -SU=$(command -v su) -SED=$(command -v sed) -COPY=$(command -v cp) -MOVE=$(command -v mv) -CAT=$(command -v cat) -CHDIR="cd" -MKDIR=$(command -v mkdir) -DELETE="$(command -v rm) -rf" -CHMOD=$(command -v chmod) -CHOWN=$(command -v chown) -TAR="$(command -v tar) -jxvf" -RMDIR="$(command -v rm) -rf" -GROUPID=1000 -USERSHELL="/bin/bash" -BINDIR="bin" -BASEDIR="base_instance" -WORKDIR="work" -WORKGUEST=${WORKDIR}/guest_instance -WORKHOST=${WORKDIR}/host_instance -SCRIPTDIR="sh_scripts" -TFDIR="tf_scripts" -DIRLIST=( "${BINDIR}" "${BASEDIR}" "${WORKDIR}" "${SCRIPTDIR}" "${TFDIR}") -BINFILES=( "create_kvm_host.py" "create_kvm_host" ) -BASEFILES=( "data.tf" "main.tf" "output.tf") -SCRIPTFILES=( "initial_config.sh") -TFFILES=( "api_key.tf" "rsa_key.tf" "rsa_pub_key.tf" "data.tf" "main.tf" "output.tf" "version.tf" ) -OTHERFILES=( "Makefile" "README.md") -KEYFILENAME="oci_api_key.pem" -# -# http(s) proxy -HTTPPROXY="http://www-proxy-hqdc.us.oracle.com:80" -HTTPSPROXY="http://www-proxy-hqdc.us.oracle.com:80" - -Usage() { - echo "" - echo "Usage:" - echo "" - echo "${0} " - echo "" - echo " : the userid for the user." - echo " : the sdk config file." - echo " : the sdk key file." - echo " : the tar file with the tool." - echo "" - echo " Creates a user with name kvmhost and userid " - echo " with groupid 1000 and in group wheel with home" - echo " directory /home/kvmhost; configures the oci-sdk for direct authentication." - echo "" -} - -MessageStd() { - local MSGNOW=$(date '+%d-%b-%Y %H:%M:%S') - echo "${MSGNOW} --- MSG --- ${1}" -} - -MessageErrBase() { - local MSGNOW=$(date '+%d-%b-%Y %H:%M:%S') - echo "${MSGNOW} --- ERR --- ${1}" -} - -MessageErrFatal() { - RETVAL="${1}" - MSG="${2}" - if [ "${RETVAL}" -ne 0 ]; then - MessageErrBase "${MSG}: ${RETVAL}" - exit 1 - fi -} - -ExitOnError() { - RETV="${1}" - ERRORMESSAGE="${2}" - SUCCESSMESSAGE="${3}" - MessageErrFatal "${RETV}" "${ERRORMESSAGE}" - MessageStd "${SUCCESSMESSAGE}" -} - -NBPAR="${#}" -if [ ${NBPAR} -ne ${EXPECTEDNBPAR} ]; then - MessageErrBase "username, userid, config, key file, private key, public key and/or tar file missing" - Usage - exit 1 -fi - -USERID=${1} -SDKCONFIG=${2} -KEYFILE=${3} -PRIVKEYFILE=${4} -PUBKEYFILE=${5} -TARFILE=${6} -MessageStd "Username is ${USERNAME}" -MessageStd "UserID is ${USERID}" -MessageStd "SDK config file is ${SDKCONFIG}" -MessageStd "SDK key file ${KEYFILE}" -MessageStd "Private key file ${PRIVKEYFILE}" -MessageStd "Public key file ${PUBKEYFILE}" -MessageStd "TAR file ${TARFILE}" -# -HOMEDIR="/home/${USERNAME}" -MessageStd "user home directory is ${HOMEDIR}" -HOMEOCI="${HOMEDIR}/.oci" -MessageStd ".oci is ${HOMEOCI}" -HOMERSA="${HOMEDIR}/.ssh" -MessageStd ".ssh is ${HOMERSA}" -HOMEOCICONFIG="${HOMEOCI}/config" -MessageStd "config file is ${HOMEOCICONFIG}" -HOMESDKKEY="${HOMEOCI}/$(basename ${KEYFILE})" -MessageStd "sdk key file is ${HOMESDKKEY}" -HOMEPRIVKEY="${HOMERSA}/$(basename ${PRIVKEYFILE})" -MessageStd "private key file is ${HOMEPRIVKEY}" -HOMEPUBKEY="${HOMERSA}/$(basename ${PUBKEYFILE})" -MessageStd "public key file is ${HOMEPUBKEY}" -HOMEAUTHKEYS=${HOMERSA}/authorized_keys -#MASTERMAKE=${HOMEGITDIR}/tests/automation/Makefile -#MessageStd "Makefile location is ${MASTERMAKE}" -# -# -${GETENT} passwd "${USERNAME}" > /dev/null 2>&1 -RETVAL=${?} -if [ ${RETVAL} -eq 0 ]; then - MessageErrFatal "${USERNAME} already exists" -fi -# -# add user -${USERADD} -c "user ${USERNAME}" -d "${HOMEDIR}" -g ${GROUPID} -G wheel -m -s "${USERSHELL}" -u "${USERID}" "${USERNAME}" -ExitOnError "${?}" "Failed to create user ${USERNAME}" "${USERNAME} created successfully." -${PASSWD} "${USERNAME}" -ExitOnError "${?}" "Failed to set password for ${USERNAME}" "Password for ${USERNAME} set successfully." -# -# create automation directories -for thisdir in "${DIRLIST[@]}" -do - ${SU} -l "${USERNAME}" -c "${MKDIR} -p ${thisdir}" - ExitOnError ${?} "Failed to create ${thisdir}" "Created ${thisdir} successfully." -done -# -# create oci sdk config directory -${SU} -l "${USERNAME}" -c "${MKDIR} ${HOMEOCI}" -ExitOnError "${?}" "Failed to create ${HOMEOCI}" "${HOMEOCI} created successfully." -# -# set permissions on oci sdk directory. -${SU} -l "${USERNAME}" -c "${CHMOD} 700 ${HOMEOCI}" -ExitOnError "${?}" "Failed to ${CHMOD} 700 ${HOMEOCI}" "${HOMEOCI} permission set to 700 successfully." -# -# copy sdk config file -${SU} -l "${USERNAME}" -c "${COPY} ${SDKCONFIG} ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to ${COPY} ${SDKCONFIG} to ${HOMEOCICONFIG}" "Copied ${SDKCONFIG} to ${HOMEOCICONFIG} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMEOCICONFIG}" "${HOMEOCICONFIG} permissions set to 600 successfully." -# -# copy key files and update config file -${SU} -l "${USERNAME}" -c "${COPY} ${KEYFILE} ${HOMEOCI}" -ExitOnError "${?}" "Failed to ${COPY} ${KEYFILE} to ${HOMEOCI}" "Copied ${KEYFILE} to ${HOMEOCI} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMESDKKEY}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMESDKKEY}" "Executed ${CHMOD} 600 ${HOMESDKKEY} successfully" -# "${SED} -i /key_file/c\"key_file=${HOMESDKKEY}\" ${HOMEOCICONFIG}" -${SU} -l "${USERNAME}" -c "${SED} -i /key_file/c\"key_file=${HOMESDKKEY}\" ${HOMEOCICONFIG}" -ExitOnError "${?}" "Failed to update ${HOMEOCICONFIG}" "Updated ${HOMEOCICONFIG} successfully" -# -# create ssh directory -${SU} -l "${USERNAME}" -c "${MKDIR} ${HOMERSA}" -ExitOnError "${?}" "Failed to create ${HOMERSA}" "${HOMERSA} created successfully." -# -# set permission on ssh directory -${SU} -l "${USERNAME}" -c "${CHMOD} 700 ${HOMERSA}" -ExitOnError "${?}" "Failed to ${CHMOD} 700 ${HOMERSA}" "${HOMERSA} permission set to 700 successfully." -# -# copy private key file in place -${SU} -l "${USERNAME}" -c "${COPY} ${PRIVKEYFILE} ${HOMERSA}" -ExitOnError "${?}" "Failed to ${COPY} ${PRIVKEYFILE} to ${HOMERSA}" "Copied ${PRIVKEYFILE} to ${HOMERSA} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMEPRIVKEY}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMEPRIVKEY}" "${HOMEPRIVKEY} permissions set to 600 successfully." -# -# copy public key file in place -${SU} -l "${USERNAME}" -c "${COPY} ${PUBKEYFILE} ${HOMERSA}" -ExitOnError "${?}" "Failed to ${COPY} ${PUBKEYFILE} to ${HOMERSA}" "Copied ${PUBKEYFILE} to ${HOMERSA} successfully." -${SU} -l "${USERNAME}" -c "${CHMOD} 600 ${HOMEPUBKEY}" -ExitOnError "${?}" "Failed to ${CHMOD} 600 ${HOMEPUBKEY}" "${HOMEPUBKEY} permissions set to 600 successfully." -# -# authorized_keys -${SU} -l "${USERNAME}" -c "${COPY} ${PUBKEYFILE} ${HOMEAUTHKEYS}" -ExitOnError "${?}" "Failed to ${COPY} ${PUBKEYFILE} to ${HOMEAUTHKEYS}" "Copied ${PUBKEYFILE} to ${HOMEAUTHKEYS} successfully." -# -# expand tar file -${SU} -l "${USERNAME}" -c "${CHDIR} ${WORKDIR}; ${TAR} ${TARFILE}" -ExitOnError "${?}" "Failed to expand ${TARFILE}" "${TARFILE} successfully expanded" -# -# copy bin in place -for binfile in "${BINFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKHOST}/bin/${binfile} ${HOMEDIR}/bin" - ExitOnError ${?} "Failed to copy ${binfile} in place." "Copied ${binfile} in place successfully" -done -# -# copy scripts in place -for scriptfile in "${SCRIPTFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKHOST}/sh_scripts/${scriptfile} ${HOMEDIR}/sh_scripts" - ExitOnError ${?} "Failed to copy ${scriptfile} in place." "Copied ${scriptfile} in place successfully" -done -# -# copy basefiles in place -for basefile in "${BASEFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKHOST}/base_instance/${basefile} ${HOMEDIR}/base_instance" - ExitOnError ${?} "Failed to copy ${basefile} in place." "Copied ${basefile} in place successfully" -done -# -# copy tffiles in place -for tffile in "${TFFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKHOST}/tf_scripts/${tffile} ${HOMEDIR}/tf_scripts" - ExitOnError ${?} "Failed to copy ${tffile} in place." "Copied ${tffile} in place successfully" -done -# -# copy Makefile and README.md -for otherfile in "${OTHERFILES[@]}" -do - ${SU} -l "${USERNAME}" -c "${MOVE} ${HOMEDIR}/${WORKDIR}/${otherfile} ${HOMEDIR}" - ExitOnError ${?} "Failed to copy ${otherfile} in place." "Copied ${otherfile} in place successfully" -done -# -# cleanup -${SU} -l "${USERNAME}" -c "${RMDIR} ${HOMEDIR}/${WORKDIR}/*" -ExitOnError ${?} "Failed to cleanup ${HOMEDIR}/${WORKDIR}." "Cleaned up ${HOMEDIR}/${WORKDIR} successfully" -# -# done -MessageStd "Completed successfully" diff --git a/tools/kvm_image/test_image/create_kvm_instance.0.11_May_05_2022.bz2 b/tools/kvm_image/test_image/create_kvm_instance.0.11_May_05_2022.bz2 deleted file mode 100644 index 142ed80e6875ed30558ab8923ea1d04821cf11b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21192 zcmV(uKYu|NsB*-~a#r|NjU80DwRuBmlq& zU~?JnpI-02?{n_x523!_9-nt3*xdO=alY*!TLjeGBCx88RNc$=o?)hyYcc2QSr?&GDrZPwn~-ghUbyIyPAj%V9n zZR2Z4(eH12bGO*vcozHa^WR>FbjhCF9ifNYBkNbKR(qW*l+@ibwovV!1HJb9*Tr|- zcW&loo!h+VDFdCSotwG1ZQG_sD(gJE-Mi9z%Q*Y*p29?g&=XAnngV13VkXc4nhjI+ zM~Z%_>TM_LnIEK{Bs`$a5CA1K2to;vngnQMOd(Iyni^s>WM}{YdVm={Kze`xBossn zdLgQLsiu+oCX*v0${K0vHld(t>HyKB$uu-*X^;RKXe81^K?$QlG}TYdRQ(M{sv3Gv z)ek7p)6@e)KxhZ4kZ1tWrhoz@h!6r~1kll`geHb5l>H`~C}9zyvPOU!Xgxp;0iYEU zL@q7gK#E$9RKR>d6A&cAhVf*)P zUe^j<@R1Jt_JoIlxBb2ASgb)hfFKVspk6N+#tY}0+wYI;oqv{z`?%i5Hq;0SnV`|A zAb=VQVk!H32u#e4m>mX@vJ5c67Ow^#aZ;dlZF$<-W+?^HM1+wQ2t<%084y2FtO`pC zL_lOk5{L@51y`v=tt%m^30u^qf`3v;3lJz6Hj05s5JhY%!4x+N%j;i=b6-O~QIq`g z4lH7lP(jTVT*7vb;e+^dneIaUI{huFrS*RUpTQ_jwDI*w`j=9NLX;n-3eowUvHiLm z1o0W}^C2dX)BSb^A=UDILWIVy~)t%x_r15Y+?G;o*{EResQxW@Sw5iDC%dm;L`O{FBSS z*#ZUx#(nH1agIbIcgXVF6Mh(W)0{ry ze?>bf%BMPqm4gdN0P^Ll4rl;0)#dbcOZoNECt!1DX}O{V#W|>${A=NUu}KgMJ;XwR zZ5aXE8^n=i0UPjyD)O4byh7>pRZ2={m*h3!^YC^_wNbfTiPJ}+JSDHe`EExr#bX2V zjIxO+G^6|l$Td>SgE{1}v0H6)?ALc*H4xsmdD<_Vu#tU`rkL{}9=S@8 zWOFe+^Ki+WgF|ruv)`|W^yfwuaMUquO%jPptZsG9sY{#$Jr{b3a-VeW;T#=V8D-n5 z(t4|A08<<3t(PvCAe>)P-ZZf3s4mGs6=zEo%mT)g+H4HE?y%2=kqO<9>TvLbD0%dE zcOdW2vQef~7+8`d((Yo(ivAYKvuio2Lu&GJml?x(EX!<+bx_`<;kv`{G~rwgvoJwh z?8TR=EcfMU@=;%8aO%>Gp-S$$QsThq6pdnn0NK);TELK~cpyKLVq9)K9B*Q1ajn|S zC(~%K)~s#P>|_(Ai912dd+j!EUSm*hYi@0@MQVaFN=Qb=8AH_L!6FWZL_1UCnBP9` zTFu6~?MNWBd!h^R^YAaBH-V^dAi0p5R3kP?FyXs*%MyQiyuzuQ3%9 zl8~=-0*vyrx}zy|WE<(q@Fo-p0oPZfd!}7>2(U!@aBy~dSBnl2=o3KV5GCaEm9;i_ zEav0X+o_$BO(0;$YG_gTepSiqk=@3A)r#eMo;;(aJgOkd8q*Mb)JgPLjpFSdi21#* zRnMMITj9q2xjyBq7ry1Y2Oxg%A3TNvq$Syg1SDh|*9SiHHXoEZg~v8yvQa7U_qX8n z76gaUZMfM^iX5bRs-_>FC(D<4z|Et{o0>FgO20w&9%m!O>Toot(RprtPN!Y_&5n9f zyG{i=y@uT=21lO1RR^7~UA+%~YE|*9vy?A+1b3d`Q1Bun1t6jbACu=R>w=;Ikfc&1 zJM4gvq!G1*fx?L*K}iJ_k&sZXqwMEiS?|a}E5kg@un`H30t)AT&&if%Am@4k0`V6s z&?xGFY)x@Bz=Xl~Du) z5d_42DWo+y@5YTC;7tn!Ndx{+=M3fJ+Xkc6h;{F}dd=&})jBTUD|N}^zGL(9cpcXlLVl*hj>WUDg*LoFOrtcnnk;nbaBH_rBzVL*y#*ed6^@Ct zwCnJf_3`gh7{X;pNL8@`NP~=Qs4R>t1Xv|~p>W#j)IS7F`ipv685iaVuA zE}SAm5cc|m4nNh90~O2#JvvRORM}lh{s{EKsg~ACiY9}!-c8_s7Eg)s4o|jv`oHNs zk`wHICH&Msl8DHt!mK}0Hv`xm!`O0pCLPDpdrsqt^qMqq`OiPXaW*-ePuLxYSsR@W zC#alzlAMOb+~@yYok&Q%0We|Ii%u0{t z+#oK<+AnR%^;@siDf0JsV0+nYj|T*ZUH=~QA-z!b_vwDWl$7RRYSkh^mRQW5-34z) zr%HsL6{h#`i5{4*_&;3zeWcIC0q+=nC_z$3a0RD-XAgd{(=;BzcLW9^gwFp1!%ug& zS8Z2mV}{$p|9YM<1WjEb+@i+s7MF$+Cv>fbL{+Te}};o=Ke|;$0voe6{A-+OR;K{oKs( z1c~XF6CCgvTF`eDFfA^*PT8o3c5k=rObm0m!1 zi!k|sJwDu<7fgU8FYFPvNY$Ne3Er35J1`Dn${cxG9dP(9Trb-&TT%3xmzR)ru%H83 zh-)cKNHErPX&{WHYBgbqhYQ7taB6vFr#kb-k+eAR0E>qs`fEHH9sryy873kE$-@^&p(Y9dGXR_z^=4SO9qpja8Y?AA z++*D=v*r+Dx6fTa#iw}Mxg7h^SLfxz*Cx|zqS*NQ_2b8LC%LDLVGX&_y%I@{lY%(# z@(9e4b9gur-O1`Z+@m_yH%gOc>i28~GQPC;&HS_tYZ=F~c50OMYg*u_f0BUpi1D%V zuv3I3>Rx4nuDthr;7k3T)1RM|Dl9xwIyN!1G1HZudqaqButLQRz;5NC$koFc;_tSo zH?Ibk{8qglH94aTePJxr+7I znl5?>Sa@|0erivH@DsOq$``E!S;ZtM3^kd`^a|4*TFcJHTu9hRqxJFH`P@-E;DPb8 z9jbet=MeNL$)%aPlgp;S+2S^`jkRFw!VkGHUf8#X_LnIu~$zdN=V!`14~V7MTfSw)G)pD=xXP zS?N^;+u=n&3FR_JUuS^^vK(=@foED2d+Xr3O^y)mkrglE-lL0?-JP$&>Ge=9KtLI8 zao^vb9?p*?^y$%6RaI0~RaI40QehxfSaiBK9S?%j?JSV3?6rQq`F!HpY}VWfGY%mh zM&pol@P9cA``z=T_ayth=au2OYd0+7<+_fNHxvx#4XC|RtrBJJ6W!eIncFJUQ9LuQ zvQ8E9XB=~j8H1}`=&ER;7|_IP-xyO<7OgJ{YF0O#2VixC%#L>S9`7x@;I^vMD z@gi=o(9Y+Z`<*EYRnJbW%c)bw<6}i4H8Q7Yba zaQjIH5{bO=j$BR>%H8^JjMP>LbAj+~rME$g)kjX~hs+|Ob>G55yG}ie%3Vu#M6L4O zrYudR(!+14Wu>j{@4Vzt(>Pg%CB|7d>q{z~H&Jp4l(up;Qs$KJbn~f+k?lE#;~ui~ zRrvMogkmgCMQ#KVE^OvRA!cZvkU{DPW2cO^*X@kknOSY;u1I+wuUt;)HI7%5x@t&G zrMwsryfAIH)ZEx0I|N?C4*E8Dh#@x02s_3r>fIMDm#k>DUlpd(-EG znNc=$6mTgyty@5&M}!gev%a}7Q=zp8un{R3o}#Rg9M%u1db84)2336QDeVL zF0|ven=r`Dpuq~icSJQLR>{}6w(jdKsbVQ~lSl8^tlOQ=(`Z@kt^1<-M>ox37npG4 zK3q+92_mmuot!OFM^7Askh>NQn|*lRd+n-OO?2 zB;gLKGY^TWQJ6YldYE{$>s4_hZyL`e^w#>1pOxWXmify)M>aEVB=e2D!rf^cgkWDd zyJd6(;j%k@p=H=yG!Q!;U+_3gcSD1ENH9UlTc8 z4XN}czNQ7YP%P04aIn6}9vW$&;@wtB+Q~c)nfQZc04f-*>IE>>HjH<(>5K;q zot#Qo(}^uGGjvLCR!({Dt2CXXrrr4)ozQZQvPJcj+j1~h z4*t!x3$0J`c{`7XedAp>N4e7!*5V*JX~$E05wD2Lt|;-kjwvc`>D2>88f`dmtO7@A zAt62y13Q>cfBksvT_RWw8YIv3oO-wN!%G{9@T5@melC_!>EZR*I{p-bent*PKtZG_ z@5(og7X0^E$5H)6wz-w0i$-WLQW%ZH5iyx;#@Y5XSE z3Bp<5%GrxvwH3QhOvSAk(prW$vGs|hsL;^T3tg3!$)*f{aXOplaZ;y{E)cEji@X6a zZT5zIOglLF?JIKy9nVpd1&}%QloDyp!HRKg#|F=4?gx?x?J0j=A|J-JACUD;me`~! z%B56^`)f0g@AWzj`SRIN7cQj-A0Lju-`PY&hRCHnf~4#|9f7m;hzAG{0}ih_)<<7w zY0<{U-0X1{#OWy);53mCNvt?D8VU8FHmEQ{wS=t@Dn%jq1S=toDgufTNTh8FfTECp zUY5|PvlvQ%uqEsB)DRsAJ%Xf>2T(XK^=cywFrz*~kb;3}Ktv#*BA}bLFcDQ)tYRvv z3@TB&EX5NRFj-*ImfI>+5e2x8&&-Cx#G(5fACs}(96zubeym27HLDUOO9rt;S_=bG zS&p4qQqVCz-GFWzB>RMlY$(W;DQKu!ECQseqN=K*Dm)~p2!>ig5E#XX$R(hI0>~%C zy2&Mi3HLdSkVuw-TVjt1Nd+p-44{fB6cmvv6XqZ^(J_3TgX(}vFDwWb(Eag@r^;!07!Hb{S!n-Ki}iihX(qU!T4Wts6&ZP^cJ zvE*Y+q%M~p7kfi!=nnW_nh)UN;rVU$d;a^Qevg1qYqCLop0-=q{l5jD(S``i;CJOu zel`a{V=?YMKU>$>dRm%p*U(!~99l@?fc085v{g59lKk9d4mdj-vpZLJ}>7AA79>33pb=OQH{jc7$JGWy##d_nM z1+2U8!g*5RtEh371e`~!xJp+%YKYH10TMkKLaVn_c&234h(|hO$p7VddpjF>=iz{4p#6GRYHjG|Wc^sN<1_ z98%)jZ~L<#%~~*ynU?dc;i4J^HkYomS}q+j7@A>(>_EpRxw!5bwI&l~5m7^M_G^Nz z7zT>%b?C@E2#DLQFfnD>bx4?3LIu4QRc-`PS(@IB7%^d=tz^x@&4+9D_U<%!Eru>V zi>8T`vOdGtHRS{>BPEfAehk_!*NSWs69Zbys}4~JrmZH7xXG0JVa|!IW5J@4Q4Y^A z&RZeXu$i)ApVUXQ(rBmDM9ee%(=~dj7{avTd_~K{sdcI+aoJ13?+W(P`q_l# zeb`K8(w!!jDDVM-xrkaM8U#dj79}7y^71cjHRZSU{4x0F(_(L205<`IHZe`aM)Nbk zqE_8gw2fuDQK0Y*-*jzDCNd*>Hs3645Y}fRc;KIF9kY`7tzHYz6R@3ruG?m_d z>!(ZZpZ3t{@z43BdB?EN=9IpFGl?GJKXgh_Y4)-w7XNrtx2xRf=soZXef~96f?l5A zCH?&JsvY6^4s$$@v%?#Km_TOirJ83&5fIg^7^mmgZrNF3ZI!#WJ$T;R!M5AS!^~43 zKFAeWc*$_#rx1})u2C`dqLom>959BIwlbt%ZD#sI$F639{;@ZK1Il>BM7f3eq4_)X z4bXac=(?{|r&-E#hI66NnZzSLKMHa7x2pOy(C%a2^;gp}^)>_?3R1oUcU+9PmC zIKPZX76JA#$o&+l>z#0Z2j3WTMwSJFj(IQe1;*<9w2Mjn_R}jevP!m6`nfs{q5MCH zSLTYmd{ZwUv%6Pb$&-~pz%sRkI%Nt#rXl_-(nObTP&%}XZg^Y|k}fdD1M^0omX3{c zh8uz_5i27Q*3Q;kB)Bp&2&JKZv8HE+;TrqGw^%{s!`#GL5&NF=WZV-ISbCwRv>)8&9mI5%i$vDXxCal1P~#5 zk!zcg#A?eQr&wu8m!YT|y-_H?c`C{n`r@5tN;0rlGEssS>+-CA6vEgaAoL47+n%L{ zQo&r28l0Ua!0SDKz>hu#XOIC0l{9_r0@}50^LIZkgh<^aKKvp3X;LMXW)EFTsc5N7 z6(q8eVv4d$VJxXBN>W-SiV`A7k_3Yyz=5d{{OM@@fz)v^>pyBCNKrMT?hg{12C4w( z?7F4moc_Fih}(8a%E!2*TMl0GIBN>Y!#ee;wu9DVep^SfldazsBLe-WLsdllyk=!j zM*zbhBkt5N!D)hqJt6=vFVPIg*d1mABV$Bvn985LF`L@Wbq5WC97!eiGqZkSK!c-v zOxd5dXNvO&hh;O@eHfZo^^)vYSMu}EDe%q9`jsi=#GL5aLoR#8JL2vr1eVd9X=dzp zbzIERn?b%-r!Kw-BCYud+fOoTNY>mxRcOm6!yF0=Q!Kh8{-RK=&B>m0(@p>Cfh`cidK z>-eZIRvypA*-#J7`K=E(*2V4j&xiZMr>e@ULwA1@-!>c*OXx*Ufc!c5tBy(#r*keEmtJAK;}6m(MVx|gU2n> z4mhijHq+al;2p>U+jnWc-FE?QToSTF$^zrv zwX*Y`-N;2yth%|NwE51pT z7{)sn>FT*&wVLdbJ5U_@6A;WWZ8YpXw}*F-O&Tq1MO9jN3G_S6)#pEciJJy!hEs@aHRUUVY+;8AB!ATJ8tJJo{*-}Kol&??ebSNXl* znF}#57ftY&d3AH?f$;w1Ll{U)hC~1=*LL7WrcVQFErC;4=&hD@ z-TGZ7W*$c{@@{n+HeD5dAX5w)NZjSz5?rfKL_YiBsss~dnEYm@JM2JRbB~Qp1OFD5 ztUH2RUC~gXx~7g;X!K%7QG64G0~vGGUjYuVkg@~s2;-0&FGeF3_X!vnEMz26=k^Bs zt+$=}m>?%ZLWWD(JTnGBo>O_c*&Z;%2piqdl=-9`*qC=Xt{CHSjh7%A;#LOfV1nTU zj;0|L5y&%Ea!8!vu$-Hhp_C&dbZNFi2S%mryZx zecDUQi?EWe$AwO=0W!?24c6&-_E+OXeENK;2=lbe-!c2&wF6&ot68)6))sO7A^v8^ z7j)P${T)=b4F>q1-cZKU0S(`Nzq+QhJ;R9r+a;vWxi9i%_;eyL_Kf?qCth+{)?`CN zI6en1E_65g*|<{W88yT;@_E|?w5@$@*IjDo<}ji~%`RW7XW-JC@oJYDq@;rEPM(a4 z;KIE2iEzahNk_KBAj)K0CsoU7>B7h_7F?p6hl%8J7qw&D+uLbLp~i+;Z1E{ps?s5` zj2jP&YxK?kZ40(6vgEgay!cGQTI>UmBh-+*h(YkN4RnW(mR%e6<@YZer+uKRDy*4EiC?XF{}cOR0kqxk+;+FMmT z)wj}P3^cl&5`05ppN#N(9%0wpwM_Q(O1^{jUm5$+8o)}$TM+_0BWufz>)Lb<)U49x2*8QOq^2un)ztI2F?_85^%^G_hv>=U4U zr-x;T9o+QX_oHKQyCckA;=V%Oeqq;z=3G=PCeM_xb_L`lR}!C2Ef=`zHk}^l2I$rK zi^dbQ-P1_e(ZyycPaHgxB7Z4JFm^-aA21#iHT3l;dvyp<&OFjOF%DZQ(nc1l5sWiJHZxjc zga@&0=)zL(rE55pr$D0tjW)5lnd}M>-hti`ken#07tKJQD-zN_4;ky|5)aq-cFVZ( z`O$gtG-!AS1h@E1=YUL~XHqRBl1T#1V12(&r)A`>rj`5*&Gq;4LM5F{{f`Wp8 zDJfW^2b`d?r5Y31j-p|0z)<&2CpsmgFc*cuNEcAf8L(^@a0zku#6t~RR@m^Gl&lPe zu|#7d+tD?OZ7k-H?-ap`1_Q6gK6XIXc*O}Glf2`HCfG!v@y;4E1(La=sTZ;!dVGGL zhr-(Z8D%Y7YTw|6&9<#AoN`WpFG~K2wtT#+9HB-`;?$1v%FFGHMLX z6ELyn&4LD>md+akpPV&?6}oEK|Nu0#iu%S?og#Vb%CC>%@b`+@OtgqL6mb_twL0oKGG^z`F)T!-A8q&#sv zo$L%dsPG~$$MhT2n@Cc*02%8w3$LZ=M3iq9-g_J@JzhG1f&C*FAugq%nkteoQQA<`; zTYl7jO&V>Cek@Nff6!skD1Fz-@UOr0L`79s?DTiA?3Pgqrr!Gn23B~Ba&N@2}?5C=WV%{(a{|ffgOXbh~*YA)SM%+#ONFh zK2|wGi+p`O-gyc5>}Rp9O0vLJ3FK$kfZ`7 zRnG*-Ogj&kz&wu?*RD5j(`<#d?ckA}u(8j8cy$&<(7MrLEbB+5X4n7~B%reWGViw2{(2jJp&JYaa6U1gA^PI2nc z0oDWHn2CV8xi9k&Q|6(4a8OhE>-_0t4dIl?O&}LlNEMg(4TNJ}Et~xd<8SsJrWZey zJNTn7jQY$;Xh@9ME5ZgS0RDsVnDlsl*ZF>LiS+9FpFXZS=5)5wG`H%nw{EVqiv!dS zq1mXvSCF81-(7|9#76gZCG|A*XXLrdkntEr=UugYd_`~fDLH32i0vunIXB)pAwRrw7CqDnkT3T9KRHxQZ`dT6Q z{sG=(nWxtNBEvmuQe6BHF!8E-6oi-V4Q#`+HvkXxSLgheQ3=Za%}w2?E+v@Yw>aLo zDZ{mcrqb0q<1orYy5GejF*q$E*^t_wl{3AVh$%2SR7>@)uoEoaf0ZkmsLKr+c#Oo` z&YhjaD10eGNJ+4rR8dlS!?FWhjawsG~OGrp@JA4m=$qiABY4 zRG{+jH{<4bGVOq8HknirQF|p+4mFnW@Y~@y#8K9)t!r($q2?j-VK$^m?(?2x@H`b~ zwMU7Pv4&}kHa~%~+4TD7-zPV*@JBz9?mZP^J3P)0k_H$UU|v~ROp;8NVwemYP3XF} zH1&-iBVN#j4@u)FbWOdCxmK+(z`+v?7USTR*0nTdJ|r+9@m}m5K=TZUf>)%4b7_-i zJypv3S&R^yZd2bpgLSa=a$3pj;89T(6oLn+o_tR^+0Pl8hOn`Oi836S9x1xg zWq_4TB#?;3Y~HZ>dD3fI)@F@sR_jE@>sdSk9N0mJbzspxm>#k-JX2sj?U|T}q8L?< zFvc(#WFh2t^bvt3hWqes8&yfUz!W@Ibtq_Hhg}wR(Hm?@1kAI=62hO;d%w+%{0Y#M zDM649Vf*yxQ%7pR-@c|&>Y0`qnJtwG7Mdmpq_Qm$QNV(&)+5>xR7*E0E~BhO+!q93 zUYp(*638K)C#ehV_{vV8!sKZKE@BH~TS-A}5WispSrp76{Yq~Q-AJABK+|)z%i$wG zDgA>E<&>|9W1!}qN7K~YJCY&4Z@WkP0mXu4?+EqYcOfX8Y{z2r=iBfQmN75tr zLFqLvbR5-|)& zH2PR&0^mL26Xx;=YC`wkK5~Z)(&_8c$yFu^phV#prn+4FOoDa>GDs?{BHsx8ndqDJfy+S%2 zc^ean$*LGgr|BX>93+k21`1fsMK**85gp0Ag2E)iQPBpB5Xttu?->$ye*3~pZ%hRC zmxyrZ;bYD9HuY)f({%NzJT0W`UEvYu*=KDBu>eQOw;q9dc*KH z`h%%R2zw?kjsgP42p-q2O5bDAN0^6ac`JVH3S4M z2;soqGIf#Q5EdMnyu-h&Iaz+Xhlg{4#@DUcCB|YBQpHp&0BEV^fz9Cc+<6?6+9`hE zxNlX(u_z znsRf5#5bn`&n1mTq=XWfK)L#9{!h@=^@fGCbJ7i)@d!88enxb;j5;JM6O};t3err+ zInWG;vFXsYThG?j9V51J1i&}2=b-@O7L3Wn zvcPUEUfyAVQ26Tm@B-lKPS9B@ZALrPFabQgx2 zGKRNs)e0uI2`IC)bXvV_YP^aUSD1+a~VYkVh!J4W7% zqRrD3W-Y@}$84=zD^85Lb zPND$_E|2{~``eUc76g$y!S!lQozuHt2e21pK`D@dNqtftWys_yYy!#X)P-dkGw+rQ ztCEI}v#V!U5K%dP5wn1&JE8XA%;l6?w9eje-DMY$I&^QoD0At<3BLJP7FSvVv( z?BKO9P~vjaY;t8n%ok+~S1{5jw#b3rK&@yYGEf$N`Q0-FfZ3l5g;TEv;IK&AJk<;1 zn~g=a1v>sThYQpgLxi<}?i~|sJf!v=hLTQ$>yLli94;ud;W8!A8{|+n7gld!U^5y8HtDeW0AP?v0ua@eJ?WTrrvSZS&UW&oaAy3hI_l1hmBb{h zG??+neb_eWgMhiHVSGW+~h}4 z+ll7qGDeYM7}l6{%9PVFD2ND6a?V(Zg#|K`U_nco0oGA=b1Z|I%p0yaV6FAX7Fb!t z!mmTF2G~xVMy$8Bf+h62#%(F%Ni?B|=FgMnF1_8dWpF>4iM! zG}WS{*+SrWf(a*;Xdp^ZfJj_N}<`Y2TeL0fqN19BelPaYY#X2R2Wf)TVwz5EW zX)xoVj2Q@4xhSzIW@qSt;x^f@(CZii{DCCw4vtkgOz5XRW#OKT`GLIJ2^VmgrN$g3U+&}`Ac zEG?lkQRWPSl5Un*StA=X(H2GD9FoDjcT)mFk&r7G!ZU$Uib#Y5aOp#Q?PBW9s<6Xk zf@(@s&}fu~VJ#rqc(bYPWi4~}~LKab86~=mIaS-%~CJ;76MI~bi3}aT*q`S>PcM#%i)wepNCK{Lm zKsbOUZ9?c-7?`1M0YSSMV|KBlbjJ*4QuB}#u z0sA6=djc+7!a55eN!5D;eZlf|p_r#6#n(1yA@{`L)b)0BH9wMMIr;i`d;)dxFA?Zy zn0QUK5wcjzJyMz!_tq5?aPHwgt$9Jo6863}i^vn?q%g&u5-YR;#@0t+@j+oepnb(X z1F9M*dgu$o5v^e`8@mq>!hQDxhj9)d2@VBh7ot~eDx<){-Z{Vx$rDj_6s#d(5e(dw zICR&N*fGTjKb+1(0Y@}Hd;*LB>|gxsS9yTFeIUSTRkRICx`=2pPqb7jQQVKakr#)j zXReyl%+X2>mD5_r2yeYFyi`wE@tV$4KzLp-#xCWBN^#+C?3fkW+JTqiPlp8>DU^X-@m zlM@L93S^R~!(hxH!H|jw!2}~C2|Ia~X8(aPy1K6Otw7eWDcLuYV~=5BqpU2VoER)s z3_n4N5=cOZNR?7G!8)Fv$5xTpa^xKep|UrXAqcA{XhMZEQ``@KwMlg&HLKYBOd2)Yve>7waOw;gyd52?tnt`EB15u}N9AG%_6-O=C zg!MQpmP6fvq+J>!yY>11D`xr>3X*g$@q=B*TRVGVz-L^6bj`8}lDHtS#FUJ-`YB-4 zSeO)?xL$qR8=X8L1q$*~!B9u* zXm40#T^Vt0BA8{ihrA-6my%5KrH3jqFJL<)-Nf(k;pGuGk{CLtu~Mm3gV;P5mJ%N8 zkxU~MgCzziSO_W$(&jZ_KGd_iRtJC*eas-Fh9q2wEV$DXkfNE%QrgK!3Q&!SG_u$@ zsVz+jsORNf4p48wUuSTNCC)^WOB-wg@mHz(FT~(IO;7n;9q5hRk4(u6o8QK~4Pa5(*YmT5mVUdbN>? zzJS^p@x^TklT0m$K@AB*Ls++a}v$p-g z^aYVi9+dsGrYMIQ1`r^@B!UcxsDi2}EEuRFK}d`S3`L9-BC!Ev7Qp8&HTlaf|GF`b$azJUB>=Cpv;KJppwIfx z^3J0U_rDI)Kl3@+@O%Cma*M2UE9R7_?;dzhAQ9M2H$nlCQ@DUKwPNT7km2N#6m+o4 z*X2CLw6yHR9;i5!)kVV#Swz9Z8vwK{66{5&sq`PD`_e(&T16vVgHA2J%^NdI8Db$2 zTP+EuOc^FdG9pB3%Vb$2Vsj;NN&b*-7(YUOswd+Wn#6Sj5llhY9|j5a$AiNw+;0m` zCYebJsq08`aZ-SllZ>md(g^|WWfda6W9?#WAT#0$g@aPw?MO3%0sM`j@I`j#k>KsaFw%S&;!w5@A%1NIX_Tw$bG@PQWdq-hl|~p5RbE zG(B=Vju8`&js?`c5M%8gG z1>u;b-U2X(UgHM{{s6fK5oIXST)?Ifht$YxEF~xz1cURnQ5A{{0J5M}DWU{kZTT9L zM4IgC-snqtpo*sWsgoCsVeYX*N+cG;B#u z3yavh5_@Z?wVrf&4)9JO^KPvJ)`fMLUBra*jiC^LM1WkP zoN2=Ds7e_cGCfxS*0+)1!YP2`>svgsL#ugr} zVrQ@9{w>`PtDGv8mD9Ey2r$+jA+QW^$%USXs(Z)8{`pN4>9++>*;>?bA@^mL+c`{q zt!UzkEbLYXo2t-+5r7j7SR{ix*?zfk?UajKxwLmPjBXxS>u4`Bw;p-T@GSgt+l583Lo0gTq+Cq9~OqVFt!og9Wnznb6G)<`yc!3IlLy6kc7J z#ry4yDN12kUQv+28Dynm#0~?3G^SY@G@>d*hQyR6NlcC=!Z^V`e*?73;j(*b4yq@2 zLkTAX;$C|kB2JxI5t4nEx{Nb1J1R)Sd@>!?J4)5S+ggk9xe@i$DS{H^5}8VdQAQ(( zr3l&q2*CW=6ol-=CvlQNN03Kw0<8*dTph=NI3>uC9C*LI-|~mJkW(dffKL;Youx)6ebZT+A>X6vZ`XPTgP@#=Hig*c9oDj*a? z0|2n8bi4$DS+0Cn?Sc{t5)9wc`dK%zX!kF&+8ZMu22FdMTpTu<*I77o0iUspsroq{ z2vR>#XC4VH*53e|8=g(jI~4SXUTNzDArv10bx9qSN>#H0lWuABAZ~*6l8>Tp!=}R z-z|+2!vPwRz(HmJuUHL5uMC1y#x;klVG7Sp|)P$)}g{m0=v=U40Y2DBnsYci=m==_zw2ZV; z0HXyN9;j5vme|0dz%s)KRTza*2qKykkY0=}J-1n@3(KT>FMkOpFw}->s*NFXfnIz4 zdgJs0uZxd~*skf-j!7x9(%2ShDhPs$7IsNcha^EF0o-`Ym{7D!P)sTi(bD%2CQX?f zkfkLpl8`YC0_Dou+;{EG?6fv=4P++$!cV`RB8rF5drTd7UT3?hyCMF+7S0*7ok zb!f6>H{kvFc+Lwt131+Uasld)p$cpMXgmS zyvE~ICuGS%B19nw!$aVv92WQikTm?}P(UbKF$AI*A}^^-cgSFGpbMs9 zdXh29&PJE_G=rcu;k`pM3IHre}@r{xMkn1 zggI(}kf~7QJd%tc7dZT)#u7#L6tI*LUgF|CN@>hK$Oy=*(k5^0_=fKwei1d02DgdC z?4cemMI#`Ewi2)+!ANu#6ON-5c^L!gk;YHq9JLMu zgn`nL3u=$3vOBgXBSF1Xm!R9|@uI}C*%yt#sF@f|ihgXRWVS38NT#Fz$ryEz_&(q9 zPw?#ceZ)N95|aExc-L(SXe5gOCcqzwfeKiL@-|6KA8-U)LP9`lB}HzRAifl)^cXMh z0OlUz%2JTPBKV7ftC+9u0@q~{Wk@SbQ2oXX-V#d;#kU;6(1xo>R*ZJ6oJb=kL z&=~`k(ZGAT>nuG4{c%RxgX#~Xxl@Rl?0COHJ&i`*%S;~$sW=MsV~4wJ&wI?RnpIQm zJE_|w?mkL;quSO<8zDVmuhY*BW}5Om@L4ubWsS-$D*a*XmaNn>9x4+sULCTIn@mb( zZQx)v2NE(yAEbPyLB>|{tYS9)sj_&!F<-vE3XfsmiwWp{vY|7Q1=WXH#3954?|B=! zmBza%R#LVpk}2=`Q#52oF0>(96}MQYXnlbr6_O`W;=(K>iv$=T#UepfA{qwBFzEGb z0|gGS?r5l~tqw+MQ9kIQvjrs%JEe++qt+|D4y2OKn2K~jv zF_WY&PRY7Ql@Dt7otwOmBgIswao-WYvz|{G4hOq=d$ZbLH54w8i5nEgGAj~DRAUrG zN;Fl1n1(UQMFC{SK|yXKOw+IC+46s)lh4L{n16HxB-0qZ)V0=8Tdn0x7{_vHH00Rw z3C9575z4qMsIpGNnNxY}EN*S(K6@(PfM#K4F)@j1#ab+r=AumnW(_C}fZ#x--s*ue z+gvS5L^;k-(&?2I>gA$y`XKKk>ati>qNx>OJ6i@G1j2Dgf=gj)N78I(tLhsv6Hq+x zR>>I;89@-%3m_~;!x}k3s8ManBA(KtZ9>*n-i3gR39(9nM@Ud&kffy%7=}=+h(T3E zMhLMGS&W$l8pa~4SbJ4-J!RhS6@uAq3WT=EqJctLsIm%`tl}&UL8YXHWsPeJRVG?2 zb^~-qhU*a^kywcc03OCAlGxFKXo^X!F(AX_0&S6sAjL(IVJ?vZ0=NVB0$m2h@D{@O z_58T12Rj>M?(7UrKzOK-LvIa1!7vmlPCJ%`N?74jYIZXlW0j3sjWLGPtq_#l21yy6 zdgGd;7O5c~aL6(Z1?x$G*=#~mmc?6bC%ES)u_1gr^q&61M=|W@^T(~w_|G#nUhD9& zxwJDT{f&`1qH4z62e#YCu={NP3QRwrr+|+jPC+pM(^F8Kj`L{oPYW4VKY28WF|1Ny z49amSZS%}v!zI%QR4PKnMVKoLk<`s{^e0)eJO^^mZb%<`SVL5eWFRno3NL`!u>1fr z0O8XBQ!t$j=x|ITDwqa$4?-%Kr_KCKkWk1ok|`&!S-6KuB&hq}8;5H32|}cw40%8i zu^y@*kYry=Wl*jTv`vBS5s_#YFK`K9%vuu7%h)vIHFm)tU!iE3b_!EI%$zNJ2NRGcC6kDG#J}}Z^Zr3 z7x1MIE>Iwzsu7KJ?bq zhhgf(-69`?2o8d6WpnO$2%Uq)FvU}3pkiDY2smoX6@6pepDeH`@a2dSzdUc2V^v=h zq~%ilNrdmzX1$Wi)TkQZ;q&>^SHEI6a&4^~S-svW+XnX7?2T}-f;JZmAy*C)BuZs% zQ4s?iNd);JA(mo-W(y^|QP+S|4MN^BV;kp3H*W8vsk&^TTd`mW0RSMK;NgzmNA&dd zdT#YGz%9>K#izLS;&CHxHmRs^kbZOWHg+l!cc%uA0{S8 zk?%e9G%w5Z$!-r&i-1@pAhCexL>EQ&K)vK6^%KbXY03lfn|@!T$aUEsE84FkY@1_f zT|?xXo3qS3+;{;alp+|E4k1HvR|i?;wzmEa;oYRs+5uAe%(w=LqM$YGe;CEGQRYoB zB?J=28L5{Gb%wR9Dh>?SQ0Wi4d7expMM&|oBNjzTab$;;Ojy2wJbC4mT6kxNvR%s2 z^PHkQ{y^A0zh6#I1o*rO>xiFN;qt47#$$aoO)M?SFKR3{QbAlb&JlG1)Et9H5yd$U zA#&kN;^DRWFbP=LJ4Cz1!f0py=cZRl zjMF69BmpM?VI~$h79w~YT(4s~ibp!zM$<^vjWv0`&WP%a#s!dSGApID3oSi?X_l*4 zT9ibvRYXP=x5)swDApE1VHzMX5-<@g7ZNcpLr@t+N!pR`8~0&O&D&TTUf`O|fuV!Y zVq``p1M`aRI|jp$Chb|9ww2FWSSb_sz(;Ii5)lE2rf74tw5@W!K0X-m<1&)K(QN|Sa99jXhaM@B7jAl8- z+ryWc=a*;0v2l}H+vRUa+9M?-jVFEH*(pprRC?!a zO&$+fhhC}4Y#r!>CDa1W@M4Gw+o>+7-VR=2lCNV-(E}Y`y$pkloOXdQoNhxh(?Dr+ zr0zn)MO1Y&jResK27t&yN^>F=U=A+G!2k+qj@5@iLj+?Xz^WoD$qC+elMMtzmULdl ztDTBL2v|c1=Lj;2LlJ8UE+r0eAeR);MF%cOVPVgOy0_DO3U?K(027&*dx)L?#9$MW z!?eWrS31i5WH*DzvTq~Ghoz)g6_cQnGbt1zh~z;TF|^SrvMib`X>^t$kXZ=ApsLVS zh@{n?MOxlw9r$>;GV&6lVv}NKrKC(1>_N|IU@+>4eBmTU-V(5Y2sMFnTBxdROzKi4 z2S$3dxkSAoE^?xx9QE;nrQ_qc+$D}v0ar*HIf0ah*7x`)t6n&7B<6RI5a3ZPIHWa3 zDj4u+zQ{mU^MdnCz^cKpsF)v>l_c2Ws^o;3W=RqvrzjZVSa* zj@w}_1_>^%iHJ-{4M7q_%gc^YO;Z&MSjibCTAQAnVZ5A2uy@Hg2z$ZYclVKGPST`~ zHYQ67Og-rt8rux{<9!|Ie9jW79jR#>aj|_+J6-N(hUi8Ngi^#rJtGq=xM~f-bKlvJ zyE7<6FxK_$1EnR*w%bk(>3_~MQ31fcG4AT(pNTSCJ@1&Ed=}xFsGNiUd!^wT(>;!C(#+v9to2PxteTg1+ z<@dv3azEM!vrrg;5I(sigCe0q9+)hOA=}XeoEanxlCV)>)UYcMh=f?776f7_$rV<@ zbh36o#Nz@9AI9cB2-s5Vh->^R>Gt-*l93+d1>7^%U4J}u6*YiNO%s9nrKUn$_J*V6&q*nGFV~q2B z=V7ZNt?=WewF%^p=1N0w<2Xkvvui(c4W>GVCsjmqs zKMftKVwS?hSbm7BV=C9eD_^L{d3osG{s0aL0I(%7!r=)e0cp#2aN&Ww3;|&jv{+z< z_@?+v8|G*mKpw!qIF!DAEDCERM+t%beC+J;HLZWV_9`C{@RcwF0W6h@yA6A7+p>0n zxGH8FOrzB{2W+(+WD$l!K{9&;H}7lNhUON)^$~48sPq<3Wf0v|!?d802Zc=(Q7Mg+ zDapYP0o?8!I30)!HfSAT?n7wMph7z4%D3Qt@^F%D=yzQc>!b7jr9H;)8CKN}j(uo5 z@bn1_upA2Pq@o29!=udHBLwb}HnXKco+PKXNTZdt$JTu3rxWp>Mtsbx$+it+GLhrF ze0381LFj-rV&qluNPv9;$rWS}2!l1GKuu?ss^P&z(CzXTYtguDXmEj8Ji~b3m?Yf5 zKIk)^tI*jF1e@!k=87;e`9mc$1)%xNc4>6Wc;bU`i<|}spneoG3^PbZkbs^H0cngy zklK38vK_%dVHuVzn>Pp=4uQsAD`7aYfN&N9MR#v7!U-VXH#~u?!kW2cwxEbMTvWOP zik8&kWHtj}XIjY*27|-Uc|ljbPR`)7s>($DK`Lq=Yqxhe z_rx%09mSs1ca2pGhq7O_R&J>Lf?3~d diff --git a/tools/kvm_image/test_image/guest_instance/bin/create_guest_vm b/tools/kvm_image/test_image/guest_instance/bin/create_guest_vm deleted file mode 100755 index 91512e67..00000000 --- a/tools/kvm_image/test_image/guest_instance/bin/create_guest_vm +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - - -# utility assists with configuring iscsi storage on Oracle Cloud -# Infrastructure instances. See the manual page for more information. - - -_PY3=/usr/bin/python3 -s_dir=${HOME}/bin - - -exec ${_PY3} ${s_dir}/create_guest_vm.py "$@" diff --git a/tools/kvm_image/test_image/guest_instance/bin/create_guest_vm.py b/tools/kvm_image/test_image/guest_instance/bin/create_guest_vm.py deleted file mode 100755 index 2dddbab2..00000000 --- a/tools/kvm_image/test_image/guest_instance/bin/create_guest_vm.py +++ /dev/null @@ -1,859 +0,0 @@ -#!/bin/python3 -""" -Create a kvm guest on a kvm image. -""" -import argparse -import os -import random -import re -import socket -import stat -import subprocess -import sys -import uuid -from ipaddress import IPv4Address -from ipaddress import IPv4Network - -ip_path = '/sbin/ip' -oci_network_path = '/bin/oci-network-config' -oci_iscsi_path = '/bin/oci-iscsi-config' -oci_kvm_path = '/bin/oci-kvm' - -vnic_fields = ['state', - 'link', - 'status', - 'ipaddress', - 'vnic', - 'mac', - 'hostname', - 'subnet', - 'routerip', - 'namespace', - 'index', - 'vlantag', - 'vlan'] - -pool_fields = ['name', - 'uuid', - 'autostart', - 'active', - 'persistent', - 'volumes', - 'state', - 'capacity', - 'allocation', - 'available'] - -volume_attached_fields = ['iqn', - 'name', - 'ocid', - 'persistentportal', - 'currentportal', - 'state', - 'device', - 'size'] - -volume_all_fields = ['name', - 'size', - 'attached', - 'ocid', - 'iqn', - 'compartment', - 'availabilitydomain'] - -ks_templates = { - 'ol7': - { - 'passthrough': 'kickstart_direct_template_ol7', - 'bridge' : 'kickstart_bridge_template_ol7' - }, - 'ol8': - { - 'passthrough': 'kickstart_direct_template_ol8', - 'bridge': 'kickstart_bridge_template_ol8' - }, - 'ol9': - { - 'passthrough': 'kickstart_direct_template_ol9', - 'bridge': 'kickstart_bridge_template_ol9' - } -} - -user_name = 'guest' -user_password = 'fXV[E<,8' -root_password = 'fXV[E<,8' -disk_name_prefix = 'oci_kvm_vm_disk_' -pool_name_prefix = 'oci_kvm_image_pool_' -pool_size = '128' -disk_size = '51' -# vcpus = '2' -# memory = '4096' -network_name = 'oci-kvm-bridge' -bridge_ip = '192.168.100.1' -log_output = '' - - -def parse_args(): - """ - Parse command line parameters. - - Returns - ------- - namespace parsed arguments. - """ - parser = argparse.ArgumentParser(description='Create kvm guest on kvm image.') - parser.add_argument('-d', '--distro', - action='store', - type=str, - choices=['ol7', 'ol8', 'ol9'], - required=True, - help='Distribution to be installed, [ol7|ol8|ol9]') - parser.add_argument('-t', '--network-type', - action='store', - type=str, - choices=['bridge', 'passthrough'], - required=True, - help='Type of network connection to vm, bridged or passthrough') - parser.add_argument('-s', '--storage-type', - action='store', - type=str, - choices=['disk', 'pool'], - required=True, - help='Type of disk for the vm.') - parser.add_argument('-i', '--iso-file', - action='store', - type=str, - required=True, - help='iso file name as stored in /isos') - parser.add_argument('-o', '--os-variant', - action='store', - type=str, - required=True, - help='os-variant for kvm.') - parser.add_argument('-c', '--cpus', - action='store', - default='2', - type=str, - help='Number of vcpus, default is 2.') - parser.add_argument('-m', '--memory', - action='store', - default='4', - type=str, - help='Amount of memory in GBs, default is 4.') - parser.add_argument('-v', '--volume-size', - action='store', - default='51', - type=str, - help='Size of root volume in GBs, default is 51.') - parser.add_argument('-p', '--pool-size', - action='store', - default='128', - type=str, - help='Size of disk pool in GBs, default is 128.') - parser.add_argument('-b', '--bare-metal', - action='store_true', - help='Is a bare-metal host.') - return parser - - -def list_to_str(somelist): - """ - Convert a list to a string. - - Parameters - ---------- - somelist: list - the list. - - Returns - ------- - str: the converted list. - """ - return ' '.join(str(x) for x in somelist) - - -def run_cmd(cmd): - """ - Run a command using subprocess. - - Parameters - ---------- - cmd: list - The command. - - Returns - ------- - The command output. - """ - print_par_val('execute', '%s' % list_to_str(cmd)) - return subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode('utf-8').splitlines() - - -def get_route_info(): - """ - Collect route info. - - Returns - ------- - str: the route info - """ - cmd = [ip_path, '-4', 'route', 'ls'] - return run_cmd(cmd) - - -def get_default_gw(route_info): - """ - Get the default gateway. - - Parameters - ---------- - route_info: str - ip route ls output. - - Returns - ------- - The default gateway. - """ - for iface in route_info: - if 'default via' in iface: - return re.findall(r"([\w.][\w.]*'?\w?)", iface)[2] - return None - - -def get_ip_address(): - """ - Get the ipv4 address. - - Returns - ------- - str: the ipv4 address. - """ - return socket.gethostbyname(socket.gethostname()) - - -def get_def_interface(route_info): - """ - Get the default ipv4 interface. - - Parameters - ---------- - route_info: str - ip route ls output. - - Returns - ------- - the default network interface. - """ - for iface in route_info: - if 'default via' in iface: - return re.findall(r"([\w.][\w.]*'?\w?)", iface)[4] - return None - - -def get_nameserver(): - """ - Get the nameserver from resolv.conf. - - Returns - ------- - str: the nameserver ipv4 - """ - - with open('/etc/resolv.conf', 'r') as fn: - resolv = fn.read() - for rec in resolv.splitlines(): - if rec.startswith('nameserver'): - return rec.split()[1] - return None - - -def get_netmask(route_info, ifc): - """ - Generate the netmask. - - Parameters - ---------- - route_info: str - ip route ls output. - ifc: str - interface. - - Returns - ------- - str: the netmask. - """ - for iface in route_info: - if 'dev %s proto kernel' % ifc in iface: - return IPv4Network(iface.split()[0]).netmask.compressed - return None - - -def validate_os_variant(variant): - """ - Verify if the supplied os variant is valid on this server. - - Parameters - ---------- - variant: str - The os short variant. - - Returns - ------- - bool: True or False. - """ - cmd = ['osinfo-query', '--fields', 'short-id', 'os'] - os_variants = [x.strip() for x in run_cmd(cmd)] - return variant in os_variants - - -def create_vnic(name): - """ - Create a vnic. - - Parameters - ---------- - name: str - vnic name - - Returns - ------- - str: create vnic output. - """ - cmd = [oci_network_path, 'attach-vnic', '--name', name] - return subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode('utf-8').splitlines() - - -def create_disk(name, size): - """ - Create a iscsi volume. - - Parameters - ---------- - name: str - volume name. - size: str - volume size in GB - - Returns - ------- - str: create volume output. - """ - cmd = [oci_iscsi_path, 'create', - '--attach-volume', - '--volume-name', name, - '--size', size] - return run_cmd(cmd) - - -def create_pool(name, size): - """ - Create a kvm pool. - - Parameters - ---------- - name: str - pool name - size: - str: size in GB - - Returns - ------- - str: create pool output - """ - pool_uuid = get_pool_data('name', name, 'uuid') - if pool_uuid is None: - create_disk_data = create_disk(name, size) - print_par_val('create disk data', create_disk_data) - get_iqn_ocid(name) - disk = get_volume_data('name', name, 'device') - cmd = [oci_kvm_path, 'create-pool', - '--disk', '/dev/' + disk, - '--name', name] - return run_cmd(cmd) - return name - - -def bridge_exists(bridge_name): - """ - Verify if bridge exists. - - Parameters - ---------- - bridge_name: str - name - - Returns - ------- - bool - """ - # cmd = ['/sbin/brctl', 'show'] - cmd = ['/usr/sbin/bridge', 'link', 'show'] - bridges = run_cmd(cmd) - for bridge in bridges: - if bridge_name in bridge: - print_par_val('%s' % bridge_name, 'exist') - return True - print_par_val('%s' % bridge_name, 'does not exist') - return False - - -def gen_ip_address(bridge_ipx): - """ - Generate a random ip address in range. - - Parameters - ---------- - bridge_ipx: str - bridge - - Returns - ------- - str: the ip address. - """ - bridge_ip_int = int(IPv4Address(bridge_ipx)) - ip_low = bridge_ip_int + 100 - ip_high = bridge_ip_int + 200 - return str(IPv4Address(random.randint(ip_low, ip_high))) - - -def create_bridge(name, net, bridge_ipx): - """ - Create a kvm bridge. - - Parameters - ---------- - name: str - name - net: str - ip address - bridge_ipx: str - ip address - - Returns - ------- - str: create command output. - """ - print_par_val('create bridge', 'name %s net %s bridge_ipx %s' % (name, net, bridge_ipx)) - net_link = get_vnic_data('vnic', name, 'link') - if net_link is None: - bridge_ip_int = int(IPv4Address(bridge_ipx)) - start_ip = str(IPv4Address(bridge_ip_int + 100)) - end_ip = str(IPv4Address(bridge_ip_int + 200)) - net_ip = get_vnic_data('vnic', net, 'ipaddress') - cmd = [oci_kvm_path, 'create-network', - '--network-name', name, - '--net', net_ip, - '--ip-bridge', bridge_ip, - '--ip-start', start_ip, - '--ip-end', end_ip, - '--ip-prefix', '24'] - return run_cmd(cmd) - print_par_val('net link', net_link) - return net_link - - -def get_vnic_data(index, val, field): - """ - Return val for vnic based on index. - - Parameters - ---------- - index: str - base field name. - val: str - base field value. - field: str - requested field value. - - Returns - ------- - str: the requested value, None if absent. - """ - print_par_val('get vnic data', 'index %s val %s field %s' % (index, val, field)) - cmd = [oci_network_path, 'show', '--details', '--output-mode', 'parsable'] - all_vnic_data = run_cmd(cmd) - - try: - for vnic in all_vnic_data: - vnic_list = vnic.split('#') - # write_log('vnic list: %s' % vnic_list) - if index not in vnic_fields or field not in vnic_fields: - return None - if vnic_list[vnic_fields.index(index)] == val: - return vnic_list[vnic_fields.index(field)] - except IndexError: - return None - return None - - -def get_pool_data(index, val, field): - """ - Return val for volume based on index. - - Parameters - ---------- - index: str - base field name. - val: str - base field value. - field: str - requested field value. - - Returns - ------- - str: the requested value, None if absent. - """ - print_par_val('get pool data', 'index %s val %s field %s' % (index, val, field)) - cmd = [oci_kvm_path, 'list-pool', '--output-mode', 'parsable'] - all_pool_data = run_cmd(cmd) - - for pool in all_pool_data: - pool_list = pool.split('#') - # write_log('pool list: %s' % pool_list) - if index not in pool_fields or field not in pool_fields: - return None - if pool_list[pool_fields.index(index)] == val: - return pool_list[pool_fields.index(field)] - return None - - -def get_volume_data(index, val, field): - """ - Return val for volume based on index. - - Parameters - ---------- - index: str - base field name. - val: str - base field value. - field: str - requested field value. - - Returns - ------- - str: the requested value, None if absent. - """ - print_par_val('get volume data', 'index %s val %s field %s' % (index, val, field)) - cmd = [oci_iscsi_path, 'show', '--detail', '--no-truncate', '--output-mode', 'parsable', '--all'] - all_volume_data = run_cmd(cmd) - - for vol in all_volume_data: - vol_list = vol.split('#') - if vol_list[2].startswith('ocid1.'): - if index not in volume_attached_fields or field not in volume_attached_fields: - continue - # is a volume in the 'attached' list - if vol_list[volume_attached_fields.index(index)] == val: - return vol_list[volume_attached_fields.index(field)] - else: - if index not in volume_all_fields or field not in volume_all_fields: - continue - # is a volume in the 'all' list - if vol_list[volume_all_fields.index(index)] == val: - return vol_list[volume_all_fields.index(field)] - return None - - -def create_kickstart(name, template, parameters): - """ - Generate a kickstart file from a template. - - Parameters - ---------- - name: str - kickstart path - template: str - Template path - parameters: dict - values to replace - Returns - ------- - int: number of characters written. - """ - with open(template, 'r') as ksf: - ks_template_data = ksf.read() - - for pattern, value in parameters.items(): - ks_config_data = ks_template_data.replace(pattern, value) - ks_template_data = ks_config_data - - with open(name, 'w') as ksc: - ret = ksc.write(ks_config_data) - return ret - - -def get_iqn_ocid(name): - """ - Get iqn and ocid from volume with name name. - - Parameters - ---------- - name: str - Volume name. - - Returns - ------- - No return value. - """ - - iqn = get_volume_data('name', name, 'iqn') - print_par_val('volume iqn', iqn) - ocid = get_volume_data('name', name, 'ocid') - print_par_val('volume ocid', ocid) - - -def print_par_val(parameter, value): - """ - Formatted output and log. - - Parameters - ---------- - parameter: str - key - value: str - value - - Returns - ------- - No return value - """ - global log_output - logdata = '%25s: %s' % (parameter, value) - print(logdata) - write_log(logdata) - - -def write_log(msg): - """ - Write a line to the logfile. - - Parameters - ---------- - msg: str - The message. - - Returns - ------- - No return value - """ - with open(log_output, 'a') as log: - log.write('%s\n' % msg) - log.flush() - - -def main(): - """ - main - - Returns - ------- - No return value. - """ - global log_output - # - parser = parse_args() - args = parser.parse_args() - # - memory = str(int(args.memory) * 1024) - vcpus = args.cpus - disk_size = args.volume_size - pool_size = args.pool_size - # - # hostname - hostname = 'guest-' + uuid.uuid4().hex[:6] - log_output = '/var/tmp/' + hostname + '.log' - # - # verify if iso exists - iso_file = '/isos/' + args.iso_file - if not os.path.exists(iso_file): - sys.exit('%s not found' % iso_file) - print_par_val('iso file', iso_file) - print_par_val('hostname', hostname) - # - # verify os variant - if not validate_os_variant(args.os_variant): - sys.exit('%s is not a valid os variant.' % args.os_variant) - print_par_val('os variant', args.os_variant) - # - print_par_val('network type', args.network_type) - print_par_val('network type', args.storage_type) - # - # verify ks template exists - ks_template = 'templates/%s' % ks_templates[args.distro][args.network_type] - if not os.path.exists(ks_template): - sys.exit('template %s does not exist.' % ks_template) - print_par_val('kickstart template', ks_template) - # - domain_cmd = ['--domain', hostname] - print_par_val('domain cmd', list_to_str(domain_cmd)) - # - # kickstart file - ks_file = hostname + '_ks.cfg' - print_par_val('kickstart file', ks_file) - route_info = get_route_info() - # print_par_val('route_info', route_info) - # - # default interface - default_intf = get_def_interface(route_info) - print_par_val('default interface', default_intf) - # - # default gateway - default_gw = get_default_gw(route_info) - print_par_val('gateway', default_gw) - # - # primary ip address - this_ip = get_ip_address() - print_par_val('ip address', this_ip) - # - # network mask - netmask = get_netmask(route_info, default_intf) - print_par_val('netmask', netmask) - # - # nameserver - nameserver = get_nameserver() - print_par_val('nameserver', nameserver) - # - # vnic - vnic_name='vnic_' + uuid.uuid4().hex[:4] - print_par_val('vnic name', vnic_name) - # - # if bridged, create network, if not already exists. - if args.network_type == 'bridge': - if not bridge_exists(network_name): - # - # vnic ip - vnic_output = create_vnic(vnic_name) - print_par_val('vnic_output', list_to_str(vnic_output)) - vnic_ip = get_vnic_data('vnic', vnic_name, 'ipaddress') - print_par_val('vnic_ip', vnic_ip) - create_bridge_output = create_bridge(network_name, vnic_name, bridge_ip) - print_par_val('create bridge', list_to_str(create_bridge_output)) - default_gw = bridge_ip - vnic_ip = gen_ip_address(bridge_ip) - nameserver = bridge_ip - netmask = '255.255.255.0' - print_par_val('guest network', '%s %s %s %s' % (vnic_ip, netmask, default_gw, nameserver)) - net_cmd = ['--virtual-network', network_name] - # - # passthrough - elif args.network_type == 'passthrough': - # - # vnic link - vnic_output = create_vnic(vnic_name) - print_par_val('vnic_output', list_to_str(vnic_output)) - vnic_link = get_vnic_data('vnic', vnic_name, 'link') - print_par_val('vnic_link', vnic_link) - # net_cmd = ['--net', vnic_link] - # - # vnic ip - vnic_ip = get_vnic_data('vnic', vnic_name, 'ipaddress') - print_par_val('vnic_ip', vnic_ip) - # - # network option - net_cmd = ['--net', vnic_ip] if args.bare_metal else ['--net', vnic_link] - # - # false - else: - sys.exit('Invalid network type') - print_par_val('network cmd', list_to_str(net_cmd)) - # - # if disk, create disk - if args.storage_type == 'disk': - name = disk_name_prefix + uuid.uuid4().hex[:6] - create_disk_data = create_disk(name, disk_size) - print_par_val('create disk', list_to_str(create_disk_data)) - get_iqn_ocid(name) - disk = get_volume_data('name', name, 'device') - disk_name = '/dev/' + disk - print_par_val('device name', disk_name) - storage_cmd = ['--disk', disk_name] - disk_cmd = [] - pool_name = ' ' - # - # create pool - else: - pool_name = pool_name_prefix + uuid.uuid4().hex[:6] - create_pool_data = create_pool(pool_name, pool_size) - print_par_val('create pool', list_to_str(create_pool_data)) - storage_cmd = ['--pool', pool_name] - disk_cmd = ['--disk-size', disk_size] - print_par_val('storage cmd', list_to_str(storage_cmd)) - print_par_val('disk cmd', list_to_str(disk_cmd)) - # - # root password - print_par_val('root password', root_password) - # - # user name - print_par_val('user_name', user_name) - # - # user password - print_par_val('user_password', user_password) - # - # pool name - print_par_val('pool name', pool_name) - # - # create kickstart file - params = { - '__DEVICE__': 'ens2', - '__GATEWAY__': default_gw, - '__IPADDRESS__': vnic_ip, - '__NAMESERVER__': nameserver, - '__NETMASK__': netmask, - '__HOSTNAME__': hostname, - '__ROOTPASSWORD__': root_password, - '__USERNAME__': user_name, - '__USERPASSWORD__': user_password - } - # ks_template = 'templates/%s' % ks_templates[args.distro][args.network_type] - # print_par_val('kickstart template', ks_template) - create_kickstart(ks_file, ks_template, params) - ks_path = os.getcwd() + '/' + ks_file - print_par_val('kickstart file path', ks_path) - virt_cmd = ['--virt', '--vcpus', vcpus, '--memory', memory, '--boot', 'cdrom,hd'] - print_par_val('virt cmd', list_to_str(virt_cmd)) - iso_cmd = ['--location', '/isos/' + args.iso_file] - print_par_val('iso cmd', list_to_str(iso_cmd)) - console_cmd = ['--nographics', '--console', 'pty,target_type=serial', '--console', 'pty,target_type=virtio'] - print_par_val('console cmd', list_to_str(console_cmd)) - os_cmd = ['--os-variant', args.os_variant] - print_par_val('os variant', list_to_str(os_cmd)) - ks_cmd = ['--initrd-inject', ks_path] - print_par_val('ks cmd', list_to_str(ks_cmd)) - ks_str = 'inst.ks=file:/%s' % ks_file - extra_args = ['--extra-args="%s"' % ks_str, '--extra-args="console=ttyS0,115200n8"'] - print_par_val('extra args', list_to_str(extra_args)) - autoconsole_cmd = ['--noautoconsole'] - print_par_val('autoconsole', list_to_str(autoconsole_cmd)) - create_vm_cmd = [oci_kvm_path, 'create'] \ - + domain_cmd \ - + disk_cmd \ - + storage_cmd \ - + net_cmd \ - + virt_cmd \ - + iso_cmd \ - + autoconsole_cmd \ - + console_cmd \ - + os_cmd \ - + ks_cmd \ - + extra_args - print_par_val('create vm', list_to_str(create_vm_cmd)) - - try: - createvm = open(hostname, 'w') - createvm.write('%s \n'% list_to_str(create_vm_cmd)) - createvm.write('virsh console %s\n' % hostname) - os.chmod(hostname, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) - except Exception as e: - print('*** ERROR *** failed to write to %s' % hostname) - finally: - createvm.close() - - - # create_vm = run_cmd(create_vm_cmd) - # print_par_val('vm create', list_to_str(create_vm)) - print('\n run bash %s/%s\n' % (os.getcwd(), hostname)) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol7 b/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol7 deleted file mode 100644 index ffebfffe..00000000 --- a/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol7 +++ /dev/null @@ -1,62 +0,0 @@ -#version=DEVEL -# System authorization information -auth --enableshadow --passalgo=sha512 -# Use CDROM installation media -cdrom -# Use text mode install -text -# Run the Setup Agent on first boot -firstboot --enable -ignoredisk --only-use=vda -# Keyboard layouts -keyboard --vckeymap=us --xlayouts='' -# System language -lang en_US.UTF-8 - -# Network information -network --bootproto=static --device=link --gateway=__GATEWAY__ --ip=__IPADDRESS__ --nameserver=__NAMESERVER__ --netmask=__NETMASK__ --ipv6=auto --activate -network --hostname=__HOSTNAME__ - -repo --name="Server-HighAvailability" --baseurl=file:///run/install/repo/addons/HighAvailability -repo --name="Server-ResilientStorage" --baseurl=file:///run/install/repo/addons/ResilientStorage -# Root password -rootpw --plaintext '__ROOTPASSWORD__' -# System services -services --enabled="chronyd" -# Do not configure the X Window System -skipx -# System timezone -timezone Europe/Brussels --utc -user --groups=wheel --name=__USERNAME__ --password='__USERPASSWORD__' --plaintext --gecos="__USERNAME__" -# System bootloader configuration -bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda -autopart --type=lvm -# Partition clearing information -clearpart --all --initlabel --drives=vda -# Firewall configuration -firewall --enabled --ssh -# reboot after install -reboot - -%packages -@core -chrony -kexec-tools -tmux -psmisc -firewalld -python3 -strace -tree -%end - -%addon com_redhat_kdump --enable --reserve-mb='auto' - -%end - -%anaconda -pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty -pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok -pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty -%end - diff --git a/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol8 b/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol8 deleted file mode 100644 index b13e524b..00000000 --- a/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol8 +++ /dev/null @@ -1,61 +0,0 @@ -#version=DEVEL -# System authorization information -auth --enableshadow --passalgo=sha512 -# Use CDROM installation media -cdrom -# Use text mode install -text -# Run the Setup Agent on first boot -firstboot --enable -ignoredisk --only-use=vda -# Keyboard layouts -keyboard --vckeymap=us --xlayouts='' -# System language -lang en_US.UTF-8 - -# Network information -network --bootproto=static --device=link --gateway=__GATEWAY__ --ip=__IPADDRESS__ --nameserver=__NAMESERVER__ --netmask=__NETMASK__ --ipv6=auto --activate -network --hostname=__HOSTNAME__ - -repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream -# Root password -rootpw --plaintext '__ROOTPASSWORD__' -# System services -services --enabled="chronyd" -# Do not configure the X Window System -skipx -# System timezone -timezone Europe/Brussels --utc -user --groups=wheel --name=__USERNAME__ --password='__USERPASSWORD__' --plaintext --gecos="__USERNAME__" -# System bootloader configuration -bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda -autopart --type=lvm -# Partition clearing information -clearpart --all --initlabel --drives=vda -# Firewall configuration -firewall --enabled --ssh -# reboot after install -reboot - -%packages -@core -chrony -kexec-tools -tmux -psmisc -firewalld -python3 -strace -tree -%end - -%addon com_redhat_kdump --enable --reserve-mb='auto' - -%end - -%anaconda -pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty -pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok -pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty -%end - diff --git a/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol9 b/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol9 deleted file mode 100644 index b13e524b..00000000 --- a/tools/kvm_image/test_image/guest_instance/templates/kickstart_bridge_template_ol9 +++ /dev/null @@ -1,61 +0,0 @@ -#version=DEVEL -# System authorization information -auth --enableshadow --passalgo=sha512 -# Use CDROM installation media -cdrom -# Use text mode install -text -# Run the Setup Agent on first boot -firstboot --enable -ignoredisk --only-use=vda -# Keyboard layouts -keyboard --vckeymap=us --xlayouts='' -# System language -lang en_US.UTF-8 - -# Network information -network --bootproto=static --device=link --gateway=__GATEWAY__ --ip=__IPADDRESS__ --nameserver=__NAMESERVER__ --netmask=__NETMASK__ --ipv6=auto --activate -network --hostname=__HOSTNAME__ - -repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream -# Root password -rootpw --plaintext '__ROOTPASSWORD__' -# System services -services --enabled="chronyd" -# Do not configure the X Window System -skipx -# System timezone -timezone Europe/Brussels --utc -user --groups=wheel --name=__USERNAME__ --password='__USERPASSWORD__' --plaintext --gecos="__USERNAME__" -# System bootloader configuration -bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda -autopart --type=lvm -# Partition clearing information -clearpart --all --initlabel --drives=vda -# Firewall configuration -firewall --enabled --ssh -# reboot after install -reboot - -%packages -@core -chrony -kexec-tools -tmux -psmisc -firewalld -python3 -strace -tree -%end - -%addon com_redhat_kdump --enable --reserve-mb='auto' - -%end - -%anaconda -pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty -pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok -pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty -%end - diff --git a/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol7 b/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol7 deleted file mode 100644 index 36831029..00000000 --- a/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol7 +++ /dev/null @@ -1,62 +0,0 @@ -#version=DEVEL -# System authorization information -auth --enableshadow --passalgo=sha512 -# Use CDROM installation media -cdrom -# Use text mode install -text -# Run the Setup Agent on first boot -firstboot --enable -ignoredisk --only-use=vda -# Keyboard layouts -keyboard --vckeymap=us --xlayouts='' -# System language -lang en_US.UTF-8 - -# Network information -network --bootproto=static --device=link --gateway=__GATEWAY__ --ip=__IPADDRESS__ --nameserver=__NAMESERVER__ --netmask=__NETMASK__ --ipv6=auto --activate -network --hostname=__HOSTNAME__ - -repo --name="Server-HighAvailability" --baseurl=file:///run/install/repo/addons/HighAvailability -repo --name="Server-ResilientStorage" --baseurl=file:///run/install/repo/addons/ResilientStorage -# Root password -rootpw --plaintext '__ROOTPASSWORD__' -# System services -services --enabled="chronyd" -# Do not configure the X Window System -skipx -# System timezone -timezone Europe/Brussels --utc -user --groups=wheel --name=__USERNAME__ --password='__USERPASSWORD__' --plaintext --gecos="__USERNAME__" -# System bootloader configuration -bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda -autopart -# Partition clearing information -clearpart --all --initlabel --drives=vda -# Firewall configuration -firewall --enabled --ssh -# reboot after install -reboot - -%packages -@core -chrony -kexec-tools -tmux -psmisc -firewalld -python3 -strace -tree -%end - -%addon com_redhat_kdump --enable --reserve-mb='auto' - -%end - -%anaconda -pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty -pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok -pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty -%end - diff --git a/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol8 b/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol8 deleted file mode 100644 index 6dcb3860..00000000 --- a/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol8 +++ /dev/null @@ -1,61 +0,0 @@ -#version=DEVEL -# System authorization information -auth --enableshadow --passalgo=sha512 -# Use CDROM installation media -cdrom -# Use text mode install -text -# Run the Setup Agent on first boot -firstboot --enable -ignoredisk --only-use=vda -# Keyboard layouts -keyboard --vckeymap=us --xlayouts='' -# System language -lang en_US.UTF-8 - -# Network information -network --bootproto=static --device=link --gateway=__GATEWAY__ --ip=__IPADDRESS__ --nameserver=__NAMESERVER__ --netmask=__NETMASK__ --ipv6=auto --activate -network --hostname=__HOSTNAME__ - -repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream -# Root password -rootpw --plaintext '__ROOTPASSWORD__' -# System services -services --enabled="chronyd" -# Do not configure the X Window System -skipx -# System timezone -timezone Europe/Brussels --utc -user --groups=wheel --name=__USERNAME__ --password='__USERPASSWORD__' --plaintext --gecos="__USERNAME__" -# System bootloader configuration -bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda -autopart -# Partition clearing information -clearpart --all --initlabel --drives=vda -# Firewall configuration -firewall --enabled --ssh -# reboot after install -reboot - -%packages -@core -chrony -kexec-tools -tmux -psmisc -firewalld -python3 -strace -tree -%end - -%addon com_redhat_kdump --enable --reserve-mb='auto' - -%end - -%anaconda -pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty -pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok -pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty -%end - diff --git a/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol9 b/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol9 deleted file mode 100644 index 6dcb3860..00000000 --- a/tools/kvm_image/test_image/guest_instance/templates/kickstart_direct_template_ol9 +++ /dev/null @@ -1,61 +0,0 @@ -#version=DEVEL -# System authorization information -auth --enableshadow --passalgo=sha512 -# Use CDROM installation media -cdrom -# Use text mode install -text -# Run the Setup Agent on first boot -firstboot --enable -ignoredisk --only-use=vda -# Keyboard layouts -keyboard --vckeymap=us --xlayouts='' -# System language -lang en_US.UTF-8 - -# Network information -network --bootproto=static --device=link --gateway=__GATEWAY__ --ip=__IPADDRESS__ --nameserver=__NAMESERVER__ --netmask=__NETMASK__ --ipv6=auto --activate -network --hostname=__HOSTNAME__ - -repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream -# Root password -rootpw --plaintext '__ROOTPASSWORD__' -# System services -services --enabled="chronyd" -# Do not configure the X Window System -skipx -# System timezone -timezone Europe/Brussels --utc -user --groups=wheel --name=__USERNAME__ --password='__USERPASSWORD__' --plaintext --gecos="__USERNAME__" -# System bootloader configuration -bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda -autopart -# Partition clearing information -clearpart --all --initlabel --drives=vda -# Firewall configuration -firewall --enabled --ssh -# reboot after install -reboot - -%packages -@core -chrony -kexec-tools -tmux -psmisc -firewalld -python3 -strace -tree -%end - -%addon com_redhat_kdump --enable --reserve-mb='auto' - -%end - -%anaconda -pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty -pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok -pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty -%end - diff --git a/tools/kvm_image/test_image/host_instance/base_instance/data.tf b/tools/kvm_image/test_image/host_instance/base_instance/data.tf deleted file mode 100644 index a3980226..00000000 --- a/tools/kvm_image/test_image/host_instance/base_instance/data.tf +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. diff --git a/tools/kvm_image/test_image/host_instance/base_instance/main.tf b/tools/kvm_image/test_image/host_instance/base_instance/main.tf deleted file mode 100644 index c6a47a95..00000000 --- a/tools/kvm_image/test_image/host_instance/base_instance/main.tf +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//YYYYvariable "instance_flex_memory_in_gbs" { -//YYYY description = "instance memorry size in GB." -//YYYY type = number -//YYYY} - -//YYYYvariable "instance_flex_ocpus" { -//YYYY description = "amount of instance ocpus." -//YYYY type = number -//YYYY} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "boot_volume_size_in_gbs" { - description = "size of boot volume in GBits" - type = number -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "initial_script_path" { - description = "path to initial bash script" - type = string -} - -provider "oci" { - tenancy_ocid = var.tenancy_ocid - user_ocid = var.user_ocid - private_key_path = var.oci_private_key - fingerprint = var.fingerprint - region = var.region - // auth = var.auth -} - -resource "oci_core_instance" "test_instance" { - count = "1" - availability_domain = var.availability_domain - compartment_id = var.compartment_ocid - display_name = var.instance_display_name - shape = var.shape -//YYYY shape_config { -//YYYY memory_in_gbs = var.instance_flex_memory_in_gbs -//YYYY ocpus = var.instance_flex_ocpus -//YYYY } - - create_vnic_details { - subnet_id = var.subnet_ocid - display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - } - - source_details { - source_type = var.source_type - source_id = var.source_ocid - boot_volume_size_in_gbs = var.boot_volume_size_in_gbs - } - - preserve_boot_volume = false - - metadata = { - ssh_authorized_keys = file(var.ssh_public_key) - } - - timeouts { - create = "60m" - } - -} - -// install repo. -resource "null_resource" "update_to_latest" { - - provisioner "remote-exec" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.XXXX_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - script = var.initial_script_path - } -} - -resource "null_resource" "create_tail_log" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.XXXX_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - - provisioner "file" { - content = "rm -f /var/tmp/oci-utils.log; touch /var/tmp/oci-utils.log; clear; tail -f /var/tmp/oci-utils.log" - destination = "/tmp/tail_log" - } -} - diff --git a/tools/kvm_image/test_image/host_instance/base_instance/output.tf b/tools/kvm_image/test_image/host_instance/base_instance/output.tf deleted file mode 100644 index 8cd3019a..00000000 --- a/tools/kvm_image/test_image/host_instance/base_instance/output.tf +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - description = "Private IP of created instance." - value = oci_core_instance.test_instance.*.private_ip[0] -} - -//XXXXoutput "instance_public_ip" { -//XXXX description = "Public IPs of created instance." -//XXXX value = oci_core_instance.test_instance.*.public_ip[0] -//XXXX} - -output "boot_volume_ocid" { - description = "OCID of the boot volume of the created instance." - value = oci_core_instance.test_instance.*.boot_volume_id[0] -} - -output "instance_ocid" { - description = "OCID of the created instance." - value = oci_core_instance.test_instance.*.id[0] -} - diff --git a/tools/kvm_image/test_image/host_instance/bin/create_kvm_host b/tools/kvm_image/test_image/host_instance/bin/create_kvm_host deleted file mode 100755 index 9bf12267..00000000 --- a/tools/kvm_image/test_image/host_instance/bin/create_kvm_host +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - - -# utility assists with configuring iscsi storage on Oracle Cloud -# Infrastructure instances. See the manual page for more information. - - -_PY3=/usr/bin/python3 -s_dir=${HOME}/bin - - -exec ${_PY3} ${s_dir}/create_kvm_host.py "$@" diff --git a/tools/kvm_image/test_image/host_instance/bin/create_kvm_host.py b/tools/kvm_image/test_image/host_instance/bin/create_kvm_host.py deleted file mode 100755 index 0b6cef7a..00000000 --- a/tools/kvm_image/test_image/host_instance/bin/create_kvm_host.py +++ /dev/null @@ -1,1741 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Creates scripts to create an instance using terraform. -""" -import argparse -import errno -import getpass -import inspect -import json -import logging -import os -import re -import shutil -import socket -import sys -import termios -import tty -from datetime import datetime -from subprocess import call - -import oci - -# -# locale -lc_all = 'en_US.UTF8' - -tfvars_file = 'instance_variables' -default_log = '/var/tmp/instance_config_' -default_instance_dir = '/oci_instances' -create_instance_dir = '' - -default_values = { - "os_user": "whocares", - "os_user_home": "whocares", - "auth": "whocares", - "user_ocid": "whocares", - "server_ip": "whocares", - "fingerprint": "whocares", - "oci_private_key": "whocares", - "tenancy_ocid": "whocares", - "region": "whocares", - "ssh_public_key": "whocares", - "ssh_private_key": "whocares", - "compartment_ocid": "whocares", - "source_ocid": "whocares", - "subnet_ocid": "whocares", - # "vcn_ocid": "whocares", - # "network_compartment_ocid": "whocares", - "vnic_display_name": "whocares", - "availability_domain": "whocares", - "instance_display_name": "whocares", - "shape": "whocares", - # "authentication": "whocares", - "source_type": "whocares", - "remote_user": "whocares", - # "autotest_root": "whocares", - "log_file_path": "/logs", - "initial_script_path": "whocares", - # "dns_search_domains" : ".oracle.com", - # "dns_server_ip" : "100.110.7.250", - # "http_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", - # "https_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", - # "http_no_proxy": "169.254.169.254,.oraclecloud.com,.oraclecorp.com,.us.oracle.com" -} - -_logger = logging.getLogger(__name__) - - -def print_g(msg, term=True): - """ - Write msg to stdout and to file. - - Parameters - ---------- - msg: str - The text. - term: bool - If true, write to stdout. - - Returns - ------- - No return value. - """ - if term: - print('%s' % msg) - _logger.debug(msg) - - -def parse_args(): - """ - Parse the command line arguments. - -p | --profile - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(description='Configure oci utils auto test.') - parser.add_argument('-n', '--name', - action='store', - dest='display_name', - help='The display name of the instance to create. There is no default, ' - 'if not provided, the script asks for it.') - parser.add_argument('-p', '--profile', - action='store', - dest='profile', - default='DEFAULT', - help='The profile in the cli/sdk config file, default is DEFAULT.') - parser.add_argument('-c', '--config', - action='store', - dest='configfile', - default='~/.oci/config', - help='The cli/sdk config file, default is ~/.oci/config.') - parser.add_argument('-d', '--data-directory', - action='store', - dest='datadir', - default='_DDDD_', - help='Root directory with data for auto test run, default is ~//data.') - parser.add_argument('-f', '--var-file', - action='store', - dest='varfilename', - default=tfvars_file, - help='filename to store the variables; the extension .tfvars.json is added automatically.') - parser._optionals.title = 'Arguments' - args = parser.parse_args() - return args - - -def _clear(): - """ - Clear screen. - - Returns - ------- - bool: True - """ - _ = call('clear' if os.name == 'posix' else 'cls') - return True - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def _is_int(string_data): - """ - Verifies if string is a valid int. - - Parameters - ---------- - string_data: str - The string to be evaluated. - - Returns - ------- - bool: True on success, false otherwise. - """ - return re.match(r"[-+]?\d+$", string_data) is not None - - -def _get_current_user(): - """ - Get the current username. - - Returns - ------- - str: the username. - """ - return getpass.getuser() - - -def _get_current_user_home(): - """ - Get the home directory of the current user. - - Returns - ------- - str: the full path of the home directory. - """ - return os.path.expanduser('~') - - -def _from_stdin(prompt, default=None): - """ - Read from stdin, if default is not set to None, some input is expected. - - Parameters - ---------- - prompt: str - The stdin prompt. - default: - Default value. - - Returns - ------- - value read - """ - while True: - return_val = input('%-40s: ' % prompt) - if bool(return_val): - return return_val - if default is not None: - return default - - -def get_configdata(profile, configfile='~/.oci/config'): - """ - Read the oci sdk/cli config file. - - Parameters - ---------- - profile: str - the config profile. - configfile: str - the path of the configfile. - Returns - ------- - dict: the config data. - """ - sdkconfigfile = configfile - if configfile.startswith('~/'): - sdkconfigfile = os.path.expanduser('~') + configfile[1:] - config = oci.config.from_file(file_location=sdkconfigfile, profile_name=profile) - return config - - -class autotesttfvars: - """ - Manipulate the tfvar.json file. - """ - def __init__(self, tfvars_file): - """ - Initialise. - - Parameters - ---------- - tfvars_file: str - Full path of the tfvar.json file. - # sdkconfig: dict - # Contents of the sdk config file. - """ - self.json_file = tfvars_file - # self.sdkconfig = sdkconfig - try: - with open(self.json_file, 'rb') as tfvj: - self.jsondata = json.load(tfvj) - except Exception as e: - # - # Failed to read variable def file, falling back to idle defaults. - print_g('Failed to read %s, creating default' % self.json_file) - self.jsondata = default_values - - def __enter__(self): - return self - - def __exit__(self, xtype, value, traceback): - try: - with open(self.json_file, 'w') as tfvj: - json.dump(self.jsondata, tfvj, indent=4) - return True - except Exception as e: - raise Exception('Failed to write %s:' % self.json_file) from e - - def update_json_with_config(self, sdk_config): - """ - Update tf.json file with .oci/config data. - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g('\nCollecting data from sdk config file:') - self.jsondata['user_ocid'] = sdk_config['user'] - print_g('user ocid: %s' % sdk_config['user']) - self.jsondata['fingerprint'] = sdk_config['fingerprint'] - print_g('fingerprint %s' % sdk_config['fingerprint']) - self.jsondata['oci_private_key'] = sdk_config['key_file'] - print_g('oci_private_key: %s' % sdk_config['key_file']) - self.jsondata['tenancy_ocid'] = sdk_config['tenancy'] - print_g('tenancy_ocid: %s' % sdk_config['tenancy']) - self.jsondata['region'] = sdk_config['region'] - print_g('region: %s' % sdk_config['region']) - if _read_yn('Agree?', default_yn=True): - return True - return False - - def update_user(self, display_name): - """ - Update tf.json file with user related data. - - Parameters - ---------- - display_name: str - The instance display name - - Returns - ------- - bool: True on success, False otherwise. - """ - # - # os user data - current_user = _get_current_user() - if bool(self.jsondata['os_user']): - if _read_yn('\nReplace %s by %s' % (self.jsondata['os_user'], current_user), default_yn=True): - self.jsondata['os_user'] = current_user - else: - self.jsondata['os_user'] = _from_stdin('os user', default=current_user) - - current_user_home = _get_current_user_home() - if bool(self.jsondata['os_user_home']): - if _read_yn('Replace %s by %s' % (self.jsondata['os_user_home'], current_user_home), default_yn=True): - self.jsondata['os_user_home'] = current_user_home - else: - self.jsondata['os_user_home'] = _from_stdin('os user home', default=current_user_home) - # - # ssh keys - pub_key = current_user_home + '/.ssh/id_rsa.pub' - if bool(self.jsondata['ssh_public_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_public_key'], pub_key), default_yn=True): - self.jsondata["ssh_public_key"] = pub_key - else: - self.jsondata['ssh_publid_key'] = _from_stdin('ssh public key', default=pub_key) - priv_key = current_user_home + '/.ssh/id_rsa' - if bool(self.jsondata['ssh_private_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_private_key'], priv_key), default_yn=True): - self.jsondata["ssh_private_key"] = priv_key - else: - self.jsondata['ssh_private_key'] = _from_stdin('ssh private key', default=priv_key) - # - # initial script - self.jsondata['initial_script_path'] = self.jsondata['os_user_home'] \ - + default_instance_dir \ - + '/' \ - + display_name \ - + '/sh_scripts/initial_config.sh' - # - # ip V4 address - thisipv4 = socket.gethostbyname(socket.gethostname()) - if bool(self.jsondata['server_ip']): - if _read_yn('Replace %s by %s' % (self.jsondata['server_ip'], thisipv4), default_yn=True): - self.jsondata['server_ip'] = thisipv4 - else: - self.jsondata['server_ip'] = _from_stdin('server ip address', default=thisipv4) - return True - - def update_image(self, image_data): - """ - Update tf.json file with image related data. - - Parameters - ---------- - image_data: dict - The image data - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g(image_data) - for k, v in image_data.items(): - print_g('%30s %s' % (k, v)) - self.jsondata[k] = v - - return True - - def update_varia(self, variadata): - """ - Update various data. - - Parameters - ---------- - variadata: dict - The various data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in variadata.items(): - print_g('%30s %s' % (var_key, var_val)) - self.jsondata[var_key] = var_val - return True - - def update_gen_data(self, gendata): - """ - Update tf.json with generic data. - - Parameters - ---------- - gendata: dict - The generic data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in gendata.items(): - self.jsondata[var_key] = var_val - return True - - -def _read_nb(prompt, min_val=1, max_val=64, default_val=1): - """ - Read an integer number from stdin. - - Parameters - ---------- - prompt: str - prompt - min_val: int - the smallest possible value. - max_val: int - the largest possible value. - default_val: int - default value if no input. - - Returns - ------- - int: the number. - """ - while 1 == 1: - read_nb = input("%s ==> " % prompt) - if not bool(read_nb): - read_nb = int(default_val) - if _is_int(read_nb): - rread_nb = int(read_nb) - if min_val <= rread_nb <= max_val: - break - print_g('Value %d out of range.' % rread_nb) - else: - print_g('Invalid input: %s' % read_nb) - _logger.debug('Value read from stdin: %d' % rread_nb) - return rread_nb - - -def _select_from(some_list, prompt, default_val=0): - """ - Select an item from a list. - - Parameters - ---------- - some_list: list - list of items. - prompt: str - prompt - default_val: int - default index value if no input. - - Returns - ------- - The list element. - """ - while 1 == 1: - selected_nb = input("%s ==> " % prompt) - if not bool(selected_nb): - selected_nb = str(default_val) - if _is_int(selected_nb): - select_index = int(selected_nb) - if 0 <= select_index < len(some_list): - break - print_g('Index %d out of range.' % select_index) - else: - print_g('Invalid input: %s' % selected_nb) - _logger.debug('Selected %s', some_list[select_index]) - return some_list[select_index] - - -def select_compartment(config_dict, prompt): - """ - Select a compartment in the tenancy. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - - prompt: str - The prompt - Returns - ------- - dict: the data of the compartment. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_compartments = oci_identity.list_compartments(config_dict['tenancy']) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for comp in oci_compartments.data: - print_g('%4d %-30s %s' % (oci_compartments.data.index(comp), comp.name, comp.id)) - return _select_from(oci_compartments.data, prompt) - - -def select_vcn(config_dict, compartment_id): - """ - Select a VCN. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the VCN - """ - try: - oci_vncclient = oci.core.VirtualNetworkClient(config_dict) - oci_vcns = oci_vncclient.list_vcns(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for vcn in oci_vcns.data: - print_g('%4d %-30s %s' % (oci_vcns.data.index(vcn), vcn.display_name, vcn.id)) - return _select_from(oci_vcns.data, 'Select VCN for instance.') - - -def select_subnet(config_dict, compartment_id, vcn_id): - """ - Select a subnet. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the subnet - """ - try: - oci_subnetclient = oci.core.VirtualNetworkClient(config_dict) - oci_subnets = oci_subnetclient.list_subnets(compartment_id, vcn_id=vcn_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for subnet in oci_subnets.data: - print_g('%4d %-30s %s' % (oci_subnets.data.index(subnet), subnet.display_name, subnet.id)) - return _select_from(oci_subnets.data, 'Select subnet instance.') - - -def select_image(config_dict, compartment_id): - """ - Select an image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the image - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - # oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id).data - - oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Zero').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Custom').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Oracle Linux').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Oracle Autonomous Linux').data - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for image in oci_images_data: - # print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.id)) - print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.operating_system)) - image_data = _select_from(oci_images_data, 'Select Image') - print_g(image_data, term=False) - return image_data - - -def select_availability_domain(config_dict, compartment_id): - """ - Select an availability domain. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the availability domain. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_availability_domains = oci_identity.list_availability_domains(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for domain in oci_availability_domains.data: - print_g('%4d %-30s %s' % (oci_availability_domains.data.index(domain), domain.name, domain.id)) - return _select_from(oci_availability_domains.data, 'Select availability domain.') - - -def select_shape(config_dict, image_ocid): - """ - Select a compatible shape for the image. - - Parameters - ---------- - imageid: str - The ocid pf the image. - - Returns - ------- - The shape. - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - oci_shapes = oci_imageclient.list_image_shape_compatibility_entries(image_ocid) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for shape_dict in oci_shapes.data: - print_g('%4d %-30s' % (oci_shapes.data.index(shape_dict), shape_dict.shape)) - return _select_from(oci_shapes.data, 'Select shape.') - - -def _get_display_name(): - """ - Read instance display name from stdin. - - Returns - ------- - str: the display name. - """ - return input('Instance Display Name: ') - - -def _get_authentication_method(): - """ - Determine the authentication method. - - Returns - ------- - str: the authentication method. - """ - _ = _clear() - print_g('Authentication method.\n', term=True) - auth_methods = ['ApiKey', 'InstancePrincipal'] - for authm in auth_methods: - print_g('%4d: %s' % (auth_methods.index(authm), authm)) - method = _select_from(auth_methods, 'Authentication method:') - print_g('Selected authentication method: %s\n' % method) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return method - - -def _get_remote_user(): - """ - Get the remote username. - - Returns - ------- - str: the username. - """ - _ = _clear() - print_g('Remote user.\n', term=True) - rem_user = input('\nRemote User Name: ') - print_g('Selected remote user name: %s\n' % rem_user) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return rem_user - - -def _get_http_proxy(default_proxy): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The http proxy url. - """ - new_url = input('http proxy url\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_https_proxy(default_proxy): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The https proxy url. - """ - new_url = input('https proxy url\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_no_proxy(default_proxy): - """ - Get the no proxy list. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The https proxy url. - """ - new_url = input('no proxy\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_log_file(default_log_file): - """ - Get the log file path. - - Parameters - ---------- - default_log_file: str - The default path. - - Returns - ------- - The path tot the log file. - """ - _ = _clear() - print_g('Log file path.\n', term=True) - new_log_file = input('log file path\n [%s] (ENTER to accept default):' % default_log_file) - print_g('Selected log file path: %s\n' % new_log_file) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return new_log_file - - -def _get_dns_search_domain(): - """ - Get the dns search domain. - - Returns - ------- - str: The dns search domain, default is retrieved from /etc/resolv.conf. - """ - resolv_file = '/etc/resolv.conf' - search_domain = 'whocares' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'search' in rf_line: - search_domain = rf_line.split()[1] - break - return search_domain - - -def _get_dns_server_ip(): - """ - Get the dns server ipv4 - - Returns - ------- - str: The dns server ipv4 address., default is retrieved from /etc/resolv.conf. - """ - resolv_file = '/etc/resolv.conf' - nameserver = '8.8.8.8' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'nameserver' in rf_line: - nameserver = rf_line.split()[1] - break - return nameserver - - -def get_generic_data(): - """ - Get generic variables. - - Parameters - ---------- - gendata: str - path to generic data directory. - - Returns - ------- - dict: the generic variables. - """ - gen_data = { - # 'instance_display_name': _get_display_name(), - 'auth': _get_authentication_method(), - 'remote_user': _get_remote_user(), - # 'http_proxy_url': _get_http_proxy(default_values['http_proxy_url']), - # 'https_proxy_url': _get_https_proxy(default_values['https_proxy_url']), - # 'http_no_proxy': _get_no_proxy(default_values['http_no_proxy']), - 'log_file_path': _get_log_file(default_values['log_file_path']), - # 'dns_search_domains': _get_dns_search_domain(), - # 'dns_server_ip': _get_dns_server_ip() - } - return gen_data - - -def create_dir(dirname): - """ - Create a directory, make a backup copy if already exists. - - Parameters - ---------- - dirname: str - Full path - - Returns - ------- - bool: True on success, false otherwise. - """ - try: - if os.path.exists(dirname): - bck_name = dirname + '_%s' % datetime.now().strftime('%Y%m%d_%H%M') - os.rename(dirname, bck_name) - print_g('Renamed %s to %s' % (dirname, bck_name), term=False) - os.makedirs(dirname) - print_g('Created %s' % dirname) - except OSError as e: - if e.errno != errno.EEXIST: - print_g('Failed to create %s' % dirname, term=False) - return False - print_g('%s already exists, might cause problems.' % dirname, term=False) - return True - - -def copy_dir(src, dest): - """ - Copy a directory recursively. - - Parameters - ---------- - src:str - Source dir - dest: str - Destination dir - - Returns - ------- - bool: True on success, False otherwise - """ - try: - if os.path.exists(dest): - shutil.rmtree(dest) - shutil.copytree(src, dest, symlinks=False) - print_g('Copied %s to %s' % (src, dest)) - except Exception as e: - _logger.error('Failed to copy %s to %s: %s', src, dest, str(e)) - return False - return True - - -def write_bash(fn, cmd): - """ - Write a command to the script file fn. - - Parameters - ---------- - fn: str - Full path of the script file. - cmd: str - The string. - - Returns - ------- - bool: True or False - """ - try: - if not os.path.exists(fn): - with open(fn, 'w') as fd: - fd.write('#!/bin/bash\n') - fd.flush() - os.chmod(fn, 0o755) - with open(fn, 'a') as fd: - fd.write('%s\n' % cmd) - fd.flush() - fd.write('RETVAL=${?}\n') - fd.flush() - fd.write('if [ $RETVAL -ne 0 ]; then\n') - fd.flush() - fd.write(' echo "%s failed"\n' % cmd) - fd.flush() - fd.write(' exit $RETVAL\n') - fd.flush() - fd.write(' echo "%s succeeded"\n' % cmd) - fd.write('fi\n') - fd.flush() - return True - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - return False - - -def init_struct(instance_name): - """ - Initialise config struct. - - Parameters - ---------- - instance_name: str - The instance display name. - - Returns - ------- - dict: the config structure. - """ - # - # exec dir - data = dict() - exec_dir = inspect.getfile(inspect.currentframe()) - data['instance_display_name'] = instance_name - data['exec_dir'] = os.path.dirname(exec_dir) - data['base_exec_dir'] = os.path.dirname(exec_dir) - return data - - -def get_user_data(data): - """ - Collect operator data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - data['operator'] = _get_current_user() - data['operator_home'] = _get_current_user_home() - print_g('Username: %s' % data['operator']) - print_g('Home: %s' % data['operator_home']) - return data - - -def create_directories(data, args): - """ - Create directories for scripts. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - def_base_dir = data['operator_home'] + default_instance_dir - instance_display_name = data['instance_display_name'] - data['def_instance_dir'] = def_base_dir + '/' + instance_display_name - data['def_data_dir'] = def_base_dir + '/' + instance_display_name + '/data' - data['base_instance_dir'] = def_base_dir + '/' + instance_display_name + '/base_instance' - data['def_tf_scripts_dir'] = def_base_dir + '/' + instance_display_name + '/tf_scripts' - data['def_sh_scripts_dir'] = def_base_dir + '/' + instance_display_name + '/sh_scripts' - if args.datadir != '_DDDD_': - data['def_data_dir'] = args.datadir + '/data' - data['def_tf_scripts_dir'] = args.datadir + '/tf_scripts' - data['def_sh_scripts_dir'] = args.datadir + '/sh_scripts' - data['base_instance_dir'] = args.datadir + '/base_instance' - print_g('Default instance dir %s' % data['def_instance_dir']) - print_g('Default data dir %s' % data['def_data_dir']) - print_g('Base instance dir %s' % data['base_instance_dir']) - print_g('Default tf_scripts dir %s' % data['def_tf_scripts_dir']) - print_g('Default sh_scripts dir %s' % data['def_sh_scripts_dir']) - if not create_dir(data['def_instance_dir']): - sys.exit(1) - if not create_dir(data['def_tf_scripts_dir']): - sys.exit(1) - if not create_dir(data['def_sh_scripts_dir']): - sys.exit(1) - if not create_dir(data['def_data_dir']): - sys.exit(1) - if not create_dir(data['base_instance_dir']): - sys.exit(1) - return data - - -def copy_scripts(data): - """ - Copy the tf scripts in place. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - if not copy_dir(operator_home + create_instance_dir + '/base_instance', base_instance_dir): - print_g('Failed to copy %s' % base_instance_dir) - sys.exit(1) - def_tf_scripts_dir = data['def_tf_scripts_dir'] - if not copy_dir(operator_home + create_instance_dir + '/tf_scripts', def_tf_scripts_dir): - print_g('Failed to copy %s' % def_tf_scripts_dir) - sys.exit(1) - def_sh_scripts_dir = data['def_sh_scripts_dir'] - if not copy_dir(operator_home + create_instance_dir + '/sh_scripts', def_sh_scripts_dir): - print_g('Failed to copy %s' % def_sh_scripts_dir) - sys.exit(1) - return True - - -def update_public_ip(data, public_ip): - """ - Update the script for public or private ip. - - Parameters - ---------- - data: dict - The configuration data. - public_ip: bool - If True set for public ip. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['def_tf_scripts_dir'] - api_key = tf_scripts_dir + '/api_key.tf' - rsa_key = tf_scripts_dir + '/rsa_key.tf' - rsa_pub_key = tf_scripts_dir + '/rsa_pub_key.tf' - output_b = base_instance_dir + '/output.tf' - output_t = tf_scripts_dir + '/output.tf' - main_b = base_instance_dir + '/main.tf' - iptype = 'public' if public_ip else 'private' - print_g('operator home %s' % operator_home, term=False) - print_g('base instance dir %s' % base_instance_dir, term=False) - print_g('api key %s' % api_key, term=False) - print_g('rsa key %s' % rsa_key, term=False) - print_g('rsa_pub key %s' % rsa_pub_key, term=False) - print_g('output b %s' % output_b, term=False) - print_g('main b %s' % main_b, term=False) - print_g('iptype %s' % iptype, term=False) - - # - # tf_scripts/api_key - with open(api_key, 'r+') as fx: - api_text = fx.read() - api_text = re.sub('XXXX', iptype, api_text) - fx.seek(0) - fx.write(api_text) - print_g('api text: %s' % api_text, term=False) - fx.truncate() - # - # tf_scripts/rsa_key - with open(rsa_key, 'r+') as fx: - rsa_text = fx.read() - rsa_text = re.sub('XXXX', iptype, rsa_text) - fx.seek(0) - fx.write(rsa_text) - print_g('api text: %s' % rsa_text, term=False) - fx.truncate() - # - # tf_scripts/rsa_pub_key - with open(rsa_pub_key, 'r+') as fx: - rsa_pub_text = fx.read() - rsa_pub_text = re.sub('XXXX', iptype, rsa_pub_text) - fx.seek(0) - fx.write(rsa_pub_text) - print_g('api text: %s' % rsa_pub_text, term=False) - fx.truncate() - # - # base_instance/main - with open(main_b, 'r+') as fx: - main_text = fx.read() - main_text = re.sub('XXXX', iptype, main_text) - fx.seek(0) - fx.write(main_text) - print_g('main text: %s' % main_text, term=False) - fx.truncate() - # - # output public ip if one available - if public_ip: - # - # base_instance/output - with open(output_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//XXXX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # tf_scripts/output - with open(output_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//XXXX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def update_flex(data): - """ - Update the terraform scripts for usage with Flex shapes. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - bool: True - """ - # - # tf_scripts/main.tf - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['def_tf_scripts_dir'] - main_t = tf_scripts_dir + '/main.tf' - main_b = base_instance_dir + '/main.tf' - with open(main_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//YYYY', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # base_instance/main.tf - with open(main_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//YYYY', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def get_oci_config(data, args): - """ - Get the oci configuration. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - cfg_dict = get_configdata(args.profile, args.configfile) - print_g('Configuration') - for k, v in cfg_dict.items(): - print_g('%40s: %s' % (k, v)) - data['oci_config'] = cfg_dict - return data - - -def get_instance_compartment(data): - """ - Get the compartment data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Compartment.\n', term=True) - instance_compartment = select_compartment(data['oci_config'], "Select compartment for the instance.") - print_g(instance_compartment, term=False) - print_g('Selected compartment: %s\n' % instance_compartment.name) - data['compartment'] = instance_compartment - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_availability_domain(data): - """ - Get the availablility domain data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Availability domain.\n', term=True) - availability_domain = select_availability_domain(data['oci_config'], data['compartment'].id) - print_g(availability_domain, term=False) - print_g('Selected availability domain: %s\n' % availability_domain.name) - data['availability_domain'] = availability_domain.name - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_network_compartment(data): - """ - Get the network compartment. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Network compartment.\n', term=True) - network_compartment = select_compartment(data['oci_config'], "Select compartment for the network.") - print_g(network_compartment, term=False) - print_g('Selected network compartment: %s\n' % network_compartment.name) - data['network_compartment'] = network_compartment - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_vcn(data): - """ - Get the VCN data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Virtual cloud network.\n', term=True) - vcn = select_vcn(data['oci_config'], data['network_compartment'].id) - data['vcn'] = vcn - print_g(vcn, term=False) - print_g('Selected VCN: %s\n' % vcn.display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_subnet(data): - """ - Get the subnet data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Subnet.\n', term=True) - subnet = select_subnet(data['oci_config'], data['network_compartment'].id, vcn_id=data['vcn'].id) - data['subnet'] = subnet - print_g(subnet, term=False) - print_g('Selected subnet: %s\n' % subnet.display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_public_ip(): - """ - Request for public ip. - - Returns - ------- - bool: true or false. - """ - _ = _clear() - return True if _read_yn('Assign a public IPv4 address?') else False - - -def get_image(data): - """ - Get the image data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Image.\n', term=True) - data['image'] = select_image(data['oci_config'], data['compartment'].id) - print_g(data['image'].id, term=False) - print_g('Selected image: %s\n' % data['image'].display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_shape(data): - """ - Get the instance shape. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Shape.\n', term=True) - data['shape'] = select_shape(data['oci_config'], data['image'].id) - print_g(data['shape'], term=False) - print_g('Selected shape: %s\n' % data['shape'].shape) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_flex_data(data): - """ - Get the Flex shape data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Flex shape data.\n', term=True) - # - # memory - data['instance_flex_memory_in_gbs'] = _read_nb('Memory in GB', default_val=4, max_val=256) - print_g(data['instance_flex_memory_in_gbs'], term=False) - print_g('Selected memory size: %dGB' % data['instance_flex_memory_in_gbs']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - # cpus - data['instance_flex_ocpus'] = _read_nb('Number of OCPUs', default_val=2, max_val=18) - print_g(data['instance_flex_ocpus'], term=False) - print_g('Selected number of OCPUs: %d' % data['instance_flex_ocpus']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - return data - - -def get_boot_volume_size(data): - """ - Get the size of the boot volume in GigaBytes. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Boot Volume Size in GigaBytes', term=True) - data['boot_volume_size_in_gbs'] = _read_nb('Boot Volume Size', default_val=51, max_val=2048) - print_g(data['boot_volume_size_in_gbs'], term=False) - print_g('Selected boot volume size: %dGB' % data['boot_volume_size_in_gbs']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - return data - - -def print_config_data(xx): - """ - Print dict. - - Parameters - ---------- - xx: dict - The data to print. - - Returns - ------- - No return value. - """ - for k,v in xx.items(): - print('%30s: %s' % (k,v)) - - -def write_scripts(data): - """ - Write the scripts. - Parameters - ---------- - data: the configuration data. - - Returns - ------- - No return value. - """ - def_log_dir = data['def_instance_dir'] - print_g('Run\n' - 'terraform -chdir=%s init\n' - 'terraform -chdir=%s validate\n' - 'terraform -chdir=%s plan -var-file=%s\n' - 'terraform -chdir=%s apply -var-file=%s -auto-approve | tee %s/creation.log\n' - 'terraform -chdir=%s destroy -var-file=%s -auto-approve' - % (data['def_tf_scripts_dir'], - data['def_tf_scripts_dir'], - data['def_tf_scripts_dir'], data['tfvarsfile'], - data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir, - data['def_tf_scripts_dir'], data['tfvarsfile'])) - create_script = data['def_instance_dir'] + '/create' - if not write_bash(create_script, 'terraform -chdir=%s init' - % data['def_tf_scripts_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s validate' - % data['def_tf_scripts_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s plan --var-file=%s' - % (data['def_tf_scripts_dir'], data['tfvarsfile'])): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s apply --var-file=%s -auto-approve | tee %s/creation.log' - % (data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir)): - sys.exit(1) - destroy_script = data['def_instance_dir'] + '/destroy' - if not write_bash(destroy_script, 'terraform -chdir=%s destroy --var-file=%s -auto-approve | tee %s/destruction.log' - % (data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir)): - sys.exit(1) - print_g('\nor\n%s\n%s' % (create_script, destroy_script)) - - -def main(): - """ - Configure auto tests. - - Returns - ------- - int: 0 on success, raises exception on failure. - """ - # - # locale - os.environ['LC_ALL'] = "%s" % lc_all - # - # parse the commandline - args = parse_args() - # - # clear - _ = _clear() - # - # instance name to create - instance_display_name = args.display_name if args.display_name is not None else _get_display_name() - # - # exec dir - config_data = init_struct(instance_display_name) - # - # initialise logging - logging.basicConfig(filename=default_log + instance_display_name + '.log', - level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s (%(module)s:%(lineno)s) - %(message)s') - # - # show initial data - print_g('Display name: %s' % instance_display_name) - print_g('exec dir: %s' % config_data['exec_dir'], term=False) - print_g('base exec dir: %s' % config_data['base_exec_dir'], term=False) - # - # current user - config_data = get_user_data(config_data) - # - # initialise data structure - image_data = dict() - # - # create directories - config_data = create_directories(config_data, args) - # - # copy the scripts in place. - _ = copy_scripts(config_data) - # - # tf variable file path - config_data['tfvarsfile'] = config_data['def_data_dir'] + '/' + args.varfilename + '.tfvars.json' - print_g('tfvars file: %s' % config_data['tfvarsfile']) - # - # Get configuration data from config file. - config_data = get_oci_config(config_data, args) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - _ = _clear() - # - # compose var file. - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_json_with_config(config_data['oci_config']) - print_g('Updated variables with config data', term=True) - _ = atfv.update_user(instance_display_name) - print_g('Updated variables with operator data', term=True) - except Exception as e: - print_g('***ERROR*** %s' % str(e), term=True) - # - # Instance compartment - config_data = get_instance_compartment(config_data) - image_data['compartment_ocid'] = config_data['compartment'].id - # _ = _clear() - # - # Availability domain - config_data = get_availability_domain(config_data) - image_data['availability_domain'] = config_data['availability_domain'] - # - # Network compartment - config_data = get_network_compartment(config_data) - # - # Virtual Cloud Network - config_data = get_vcn(config_data) - # - # Subnets - config_data = get_subnet(config_data) - image_data['subnet_ocid'] = config_data['subnet'].id - # - # Public ip - image_data['assign_public_ip'] = get_public_ip() - # - # update public ip - _ = update_public_ip(config_data, image_data['assign_public_ip']) - # - # Type - image_data['source_type'] = 'image' - # - # Images - config_data = get_image(config_data) - image_data['source_ocid'] = config_data['image'].id - # - # Shape - config_data = get_shape(config_data) - image_data['shape'] = config_data['shape'].shape - # - # Boot volume size - config_data = get_boot_volume_size(config_data) - image_data['boot_volume_size_in_gbs'] = config_data['boot_volume_size_in_gbs'] - # - # is shape Flex? - if bool(re.search('Flex', image_data['shape'])): - config_data = get_flex_data(config_data) - image_data['instance_flex_memory_in_gbs'] = config_data['instance_flex_memory_in_gbs'] - image_data['instance_flex_ocpus'] = config_data['instance_flex_ocpus'] - _ = update_flex(config_data) - # - # get generic variables - gen_data = get_generic_data() - gen_data['instance_display_name'] = instance_display_name - # - # various data - varia_data = {'vnic_display_name': instance_display_name} - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_varia(varia_data) - print_g('Updated various data.') - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - # - # update tfvars file - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_image(image_data) - print_g('Updated variables with image data.') - _ = atfv.update_gen_data(gen_data) - print_g('Updated variables with generic data.') - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - # - print_g('Wrote configuration to %s' % config_data['tfvarsfile']) - # - write_scripts(config_data) - sys.exit(0) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/kvm_image/test_image/host_instance/sh_scripts/initial_config.sh b/tools/kvm_image/test_image/host_instance/sh_scripts/initial_config.sh deleted file mode 100644 index 59d4ca77..00000000 --- a/tools/kvm_image/test_image/host_instance/sh_scripts/initial_config.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -x -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http:/oss.oracle.com/licenses/upl. - -RPM=$(command -v rpm) -GREP=$(command -v grep) -FIND=$(command -v find) -SED=$(command -v sed) -MKDIR=$(command -v mkdir) -DNF=dnf -YUM=yum -SYSTEMCTL=$(command -v systemctl) -SUDO=$(command -v sudo) -INITIALLOG=/logs/initial.log -OSVERSION=$(${SED} -rn 's/.*([0-9])\.[0-9].*/\1/p' /etc/redhat-release) -${SUDO} --login mkdir -p /logs -${SUDO} --login mkdir /logs -${SUDO} --login chmod 777 /logs -${SUDO} --login echo ${OSVERSION} 2>&1 > ${INITIALLOG} -if ! command -v dnf; then -installrpm=$(command -v yum) -${SUDO} --login ${installrpm}-config-manager --enablerepo ol${OSVERSION}_developer -else -installrpm=$(command -v dnf) -${SUDO} --login ${installrpm} config-manager --set-enabled ol${OSVERSION}_developer -fi -# -# excluding the kernel can cause the install failing -# ${SUDO} --login ${installrpm} --assumeyes update --exclude=kernel*,oci-utils* 2>&1 >> ${INITIALLOG} -${SUDO} --login ${installrpm} --assumeyes install tree strace tmux iotop psmisc net-tools 2>&1 >> ${INITIALLOG} -# -# create space for storing isos for guest installs -${SUDO} --login mkdir -p /isos -${SUDO} --login mkdir /isos -${SUDO} --login chmod 777 /isos \ No newline at end of file diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/api_key.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/api_key.tf deleted file mode 100644 index 75ddeb77..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/api_key.tf +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_sdk_config" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.oci_private_key - destination = "/tmp/oci_private_key.pem" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.oci", - "/bin/sudo --preserve-env cp /tmp/oci_private_key.pem /root/.oci/$(basename ${var.oci_private_key})", - "/bin/sudo --preserve-env echo [DEFAULT] > /tmp/config", - "/bin/sudo --preserve-env echo user=${var.user_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo fingerprint=${var.fingerprint} >> /tmp/config", - "/bin/sudo --preserve-env echo key_file=/root/.oci/$(basename ${var.oci_private_key}) >> /tmp/config", - "/bin/sudo --preserve-env echo tenancy=${var.tenancy_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo region=${var.region} >> /tmp/config", - "/bin/sudo cp /tmp/config /root/.oci/config", - "/bin/sudo chmod -R 600 /root/.oci/", - "/bin/sudo chmod 700 /root/.oci", - "/bin/sudo --preserve-env mkdir -p /home/${var.remote_user}/.oci", - "/bin/sudo cp /tmp/config /home/${var.remote_user}/.oci/config", - "/bin/sudo --preserve-env chown -R ${var.remote_user}:${var.remote_user} /home/${var.remote_user}/.oci", - "/bin/sudo chmod -R 600 /home/${var.remote_user}/.oci/", - "/bin/sudo chmod 700 /home/${var.remote_user}/.oci" - ] - } -} diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/data.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/data.tf deleted file mode 100644 index 8130d272..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/data.tf +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} - diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/main.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/main.tf deleted file mode 100644 index 47361ae2..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/main.tf +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//YYYYvariable "instance_flex_memory_in_gbs" { -//YYYY description = "instance memorry size in GB." -//YYYY type = number -//YYYY} - -//YYYYvariable "instance_flex_ocpus" { -//YYYY description = "amount of instance ocpus." -//YYYY type = number -//YYYY} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "boot_volume_size_in_gbs" { - description = "size of boot volume in GBits" - type = number -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "initial_script_path" { - description = "path to initial bash script" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape -//YYYY instance_flex_memory_in_gbs = var.instance_flex_memory_in_gbs -//YYYY instance_flex_ocpus = var.instance_flex_ocpus - source_ocid = var.source_ocid - source_type = var.source_type - boot_volume_size_in_gbs = var.boot_volume_size_in_gbs - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path - initial_script_path = var.initial_script_path -} diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/output.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/output.tf deleted file mode 100644 index 2f326d2b..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/output.tf +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - value = module.base_instance.instance_private_ip -} - -//XXXXoutput "instance_public_ip" { -//XXXX value = module.base_instance.instance_public_ip -//XXXX} - -output "boot_volume_ocid" { - value = module.base_instance.boot_volume_ocid -} - -output "instance_ocid" { - value = module.base_instance.instance_ocid -} \ No newline at end of file diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/rsa_key.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/rsa_key.tf deleted file mode 100644 index b75eca2d..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/rsa_key.tf +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_private_key" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.ssh_private_key - destination = "/tmp/id_rsa" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa /root/.ssh/id_rsa", - "/bin/sudo chmod -R 600 /root/.ssh/", - "/bin/sudo chmod 700 /root/.ssh", - "/bin/sudo --preserve-env mkdir -p /home/${var.remote_user}/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa /home/${var.remote_user}/.ssh/id_rsa", - "/bin/sudo --preserve-env chown -R ${var.remote_user}:${var.remote_user} /home/${var.remote_user}/.ssh", - "/bin/sudo chmod -R 600 /home/${var.remote_user}/.ssh/", - "/bin/sudo chmod 700 /home/${var.remote_user}/.ssh" - ] - } -} diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/rsa_pub_key.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/rsa_pub_key.tf deleted file mode 100644 index c09f5b63..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/rsa_pub_key.tf +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_public_key" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.ssh_public_key - destination = "/tmp/id_rsa.pub" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa.pub /root/.ssh/id_rsa.pub", - "/bin/sudo chmod -R 600 /root/.ssh/", - "/bin/sudo chmod 700 /root/.ssh", - "/bin/sudo --preserve-env mkdir -p /home/${var.remote_user}/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa.pub /home/${var.remote_user}/.ssh/id_rsa.pub", - "/bin/sudo --preserve-env chown -R ${var.remote_user}:${var.remote_user} /home/${var.remote_user}/.ssh", - "/bin/sudo chmod -R 600 /home/${var.remote_user}/.ssh/", - "/bin/sudo chmod 700 /home/${var.remote_user}/.ssh/" - ] - } -} diff --git a/tools/kvm_image/test_image/host_instance/tf_scripts/version.tf b/tools/kvm_image/test_image/host_instance/tf_scripts/version.tf deleted file mode 100644 index 3d2fdf15..00000000 --- a/tools/kvm_image/test_image/host_instance/tf_scripts/version.tf +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} \ No newline at end of file diff --git a/tools/provisioning/gen_instance/Makefile b/tools/provisioning/gen_instance/Makefile deleted file mode 100644 index 6df74209..00000000 --- a/tools/provisioning/gen_instance/Makefile +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for creating an instance in OCI -# -# -# -# proxy -# -export no_proxy=169.254.169.254,.oraclecloud.com -# -CREATEINSTANCEPY=bin/create_instance.py -CREATEINSTANCESH=bin/create_instance -MODIFYINSTANCEPY=bin/modify_instance.py -MODIFYINSTANCESH=bin/modify_instance -OCIGPY=bin/ocig.py -OCIGSH=bin/ocig -BINARIES=$(CREATEINSTANCEPY) $(CREATEINSTANCESH) $(MODIFYINSTANCEPY) $(MODIFYINSTANCESH) $(OCIGPY) $(OCIGSH) - -BASEDATATF=base_instance/data.tf -BASEMAINTF=base_instance/main.tf -BASEOUTPUTTF=base_instance/output.tf -BASES=$(BASEDATATF) $(BASEMAINTF) $(BASEOUTPUTTF) - -TFAPITF=tf_scripts/api_key.tf -TFRSA=tf_scripts/rsa_key.tf -TFRSAPUB=tf_scripts/rsa_pub_key.tf -TFDATATF=tf_scripts/data.tf -TFMAINTF=tf_scripts/main.tf -TFVERSION=tf_scripts/version.tf -TFOUTPUTTF=tf_scripts/output.tf -TFSCRIPTS=$(TFAPITF) $(TFDATATF) $(TFMAINTF) $(TFVERSION) $(TFOUTPUTTF) $(TFRSA) $(TFRSAPUB) - -INITIALSCRIPT=gen_scripts/initial_config.sh -SHSCRIPTS=$(INITIALSCRIPT) -# -# files involved -FILELIST=Makefile README.md $(BINARIES) $(BASES) $(TFSCRIPTS) $(SHSCRIPTS) -# -TARGET=create_instance -VERSION=0.14_May_05_2022 -WRITE=@echo -CREATETAR=tar -cjvf -EXPANDTAR=tar -xjvf -MKDIR=-mkdir -p -RMFORCE=rm -rf -DELETE=rm -f -INSTALL=install --mode=755 -COPYA=cp -a -SUDO=sudo -# -# destinations -HOMEBINS=$(HOME)/bin -HOMEBASES=$(HOME)/$(TARGET)/base_instance -HOMETFSCRIPTS=$(HOME)/$(TARGET)/tf_scripts -HOMESHSCRIPTS=$(HOME)/$(TARGET)/sh_scripts -# -# tarball name -TARBALL=$(TARGET).$(VERSION).bz -# help -# -.PHONY: help -help: - $(WRITE) "help info:" - $(WRITE) " make help" - $(WRITE) " make show_version" - $(WRITE) " make tarball" - $(WRITE) " make install" - $(WRITE) " make uninstall" - -# -# version info -.PHONY: showversion -show_version: - $(WRITE) "version of $(TARGET) source is $(VERSION)" -# -# create tarball -tarball: - $(WRITE) $(BINARIES) - $(WRITE) $(FILELIST) - $(CREATETAR) $(TARBALL) $(FILELIST) -# -# create directories -bindir: - $(MKDIR) $(HOMEBINS) - -basedir: - $(MKDIR) $(HOMEBASES) - -tfscriptdir: - $(MKDIR) $(HOMETFSCRIPTS) - -shscriptdir: - $(MKDIR) $(HOMESHSCRIPTS) -# -# lists -$(BINARIES): bindir - $(WRITE) $(BINARIES) - -$(BASES): basedir - $(WRITE) $(BASES) - -$(TFSCRIPTS): tfscriptdir - $(WRITE) $(TFSCRIPTS) - -$(SHSCRIPTS): shscriptdir - $(WRITE) $(SHSCRIPTS) -# -# install -BIN: $(BINARIES) - $(INSTALL) $^ $(HOMEBINS) - -$(HOMEBASES): $(BASES) - $(COPYA) $^ $@ - -$(HOMETFSCRIPTS): $(TFSCRIPTS) - $(COPYA) $^ $@ - -$(HOMESHSCRIPTS): $(SHSCRIPTS) - $(COPYA) $^ $@ - -install: BIN $(HOMETFSCRIPTS) $(HOMEBASES) $(HOMESHSCRIPTS) - $(WRITE) "Installed" -# -# uninstall -uninstallbins: $(BINARIES) - $(foreach var,$(BINARIES),$(DELETE) $(HOME)/$(var);) - -uninstalldata: - $(RMFORCE) $(HOME)/$(TARGET) - -uninstall: uninstallbins uninstalldata - $(WRITE) "Uninstalled" \ No newline at end of file diff --git a/tools/provisioning/gen_instance/README.md b/tools/provisioning/gen_instance/README.md deleted file mode 100644 index 6bf07e05..00000000 --- a/tools/provisioning/gen_instance/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Assistance for creating a basic instance in OCI. - -## Prerequisites - -- terraform software installed -- oci-sdk installed and configured for direct authentication (for now) - -## Command line -```buildoutcfg -$ create_instance --help -usage: create_instance.py [-h] [-n DISPLAY_NAME] [-p PROFILE] [-c CONFIGFILE] - [-d DATADIR] [-f VARFILENAME] - -Configure oci utils auto test. - -Arguments: - -h, --help show this help message and exit - -n DISPLAY_NAME, --name DISPLAY_NAME - The display name of the instance to create. There is - no default, if not provided, the script asks for it. - -p PROFILE, --profile PROFILE - The profile in the cli/sdk config file, default is - DEFAULT. - -c CONFIGFILE, --config CONFIGFILE - The cli/sdk config file, default is ~/.oci/config. - -d DATADIR, --data-directory DATADIR - Root directory with data for auto test run, default is - ~//data. - -f VARFILENAME, --var-file VARFILENAME - filename to store the variables; the extension - .tfvars.json is added automatically. - -``` -## Flow -- copy this tree/tar ball and expand to a working location -- chdir to **gen_instance** directory -- `make` will show some help information -- install by executing `make install`, this will the copy template structure to a directory `~/create_instance` and the python code `create_instance.py` and the bash wrapper `create_instance` to `~/bin` -- run `~/bin/create_instance` which completes the variable data, creates a directory `~/oci_instance/` which contains the data for creating the instance, and creates create and destroy scripts. -- the code assumes the presence of **${HOME}/.ssh/id_rsa** and **${HOME}/.ssh/id_rsa.pub**. \ No newline at end of file diff --git a/tools/provisioning/gen_instance/base_instance/data.tf b/tools/provisioning/gen_instance/base_instance/data.tf deleted file mode 100644 index a3980226..00000000 --- a/tools/provisioning/gen_instance/base_instance/data.tf +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. diff --git a/tools/provisioning/gen_instance/base_instance/main.tf b/tools/provisioning/gen_instance/base_instance/main.tf deleted file mode 100644 index 708448bf..00000000 --- a/tools/provisioning/gen_instance/base_instance/main.tf +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//YYYYvariable "instance_flex_memory_in_gbs" { -//YYYY description = "instance memorry size in GB." -//YYYY type = number -//YYYY} - -//YYYYvariable "instance_flex_ocpus" { -//YYYY description = "amount of instance ocpus." -//YYYY type = number -//YYYY} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "boot_volume_size_in_gbs" { - description = "size of boot volume in GBits" - type = number -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "initial_script_path" { - description = "path to initial bash script" - type = string -} - -provider "oci" { - tenancy_ocid = var.tenancy_ocid - user_ocid = var.user_ocid - private_key_path = var.oci_private_key - fingerprint = var.fingerprint - region = var.region - // auth = var.auth -} - -resource "oci_core_instance" "test_instance" { - count = "1" - availability_domain = var.availability_domain - compartment_id = var.compartment_ocid - display_name = var.instance_display_name - shape = var.shape -//YYYY shape_config { -//YYYY memory_in_gbs = var.instance_flex_memory_in_gbs -//YYYY ocpus = var.instance_flex_ocpus -//YYYY } - - create_vnic_details { - subnet_id = var.subnet_ocid - display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - } - - source_details { - source_type = var.source_type - source_id = var.source_ocid - boot_volume_size_in_gbs = var.boot_volume_size_in_gbs -} - - preserve_boot_volume = false - - metadata = { - ssh_authorized_keys = file(var.ssh_public_key) - } - - timeouts { - create = "60m" - } - -} - -// install repo. -resource "null_resource" "update_to_latest" { - - provisioner "remote-exec" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.XXXX_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - script = var.initial_script_path - } -} - -resource "null_resource" "create_tail_log" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.XXXX_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - - provisioner "file" { - content = "rm -f /var/tmp/oci-utils.log; touch /var/tmp/oci-utils.log; clear; tail -f /var/tmp/oci-utils.log" - destination = "/tmp/tail_log" - } -} - diff --git a/tools/provisioning/gen_instance/base_instance/output.tf b/tools/provisioning/gen_instance/base_instance/output.tf deleted file mode 100644 index 8cd3019a..00000000 --- a/tools/provisioning/gen_instance/base_instance/output.tf +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - description = "Private IP of created instance." - value = oci_core_instance.test_instance.*.private_ip[0] -} - -//XXXXoutput "instance_public_ip" { -//XXXX description = "Public IPs of created instance." -//XXXX value = oci_core_instance.test_instance.*.public_ip[0] -//XXXX} - -output "boot_volume_ocid" { - description = "OCID of the boot volume of the created instance." - value = oci_core_instance.test_instance.*.boot_volume_id[0] -} - -output "instance_ocid" { - description = "OCID of the created instance." - value = oci_core_instance.test_instance.*.id[0] -} - diff --git a/tools/provisioning/gen_instance/bin/create_instance b/tools/provisioning/gen_instance/bin/create_instance deleted file mode 100644 index 66c535ba..00000000 --- a/tools/provisioning/gen_instance/bin/create_instance +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - -# utility assists with creating an oci instance. - -_PY3=/usr/bin/python3 -# s_dir=`${_PY3} -c 'import os.path ; import oci_utils.impl ; print (os.path.dirname(oci_utils.impl.__file__))' 2>/dev/null` - - -exec ${_PY3} ${HOME}/bin/create_instance.py $@ diff --git a/tools/provisioning/gen_instance/bin/create_instance.py b/tools/provisioning/gen_instance/bin/create_instance.py deleted file mode 100755 index d4bd3dd7..00000000 --- a/tools/provisioning/gen_instance/bin/create_instance.py +++ /dev/null @@ -1,1759 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Creates scripts to create an instance using terraform. -""" -import argparse -import errno -import getpass -import inspect -import json -import logging -import os -import re -import shutil -import socket -import sys -import termios -import tty -from datetime import datetime -from subprocess import call - -import oci - -# -# locale -lc_all = 'en_US.UTF8' - -tfvars_file = 'instance_variables' -default_log = '/var/tmp/instance_config_' -default_instance_dir = 'oci_instances' -create_instance_source = 'create_instance' - - -default_values = { - "os_user": "whocares", - "os_user_home": "whocares", - "auth": "whocares", - "user_ocid": "whocares", - "server_ip": "whocares", - "fingerprint": "whocares", - "oci_private_key": "whocares", - "tenancy_ocid": "whocares", - "region": "whocares", - "ssh_public_key": "whocares", - "ssh_private_key": "whocares", - "compartment_ocid": "whocares", - "source_ocid": "whocares", - "subnet_ocid": "whocares", - # "vcn_ocid": "whocares", - # "network_compartment_ocid": "whocares", - "vnic_display_name": "whocares", - "availability_domain": "whocares", - "instance_display_name": "whocares", - "shape": "whocares", - # "authentication": "whocares", - "source_type": "whocares", - "boot_volume_size_in_gbs": 51, - "remote_user": "whocares", - # "autotest_root": "whocares", - "log_file_path": "/logs", - "initial_script_path": "whocares", - # "dns_search_domains" : ".oracle.com", - # "dns_server_ip" : "100.110.7.250", - # "http_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", - # "https_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", - # "http_no_proxy": "169.254.169.254,.oraclecloud.com,.oraclecorp.com,.us.oracle.com" -} - -_logger = logging.getLogger(__name__) - - -def print_g(msg, term=True): - """ - Write msg to stdout and to file. - - Parameters - ---------- - msg: str - The text. - term: bool - If true, write to stdout. - - Returns - ------- - No return value. - """ - if term: - print('%s' % msg) - _logger.debug(msg) - - -def parse_args(): - """ - Parse the command line arguments. - -p | --profile - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(prog='create_instance', - description='Configure oci utils auto test.') - parser.add_argument('-n', '--name', - action='store', - dest='display_name', - help='The display name of the instance to create. There is no default, ' - 'if not provided, the script asks for it.') - parser.add_argument('-p', '--profile', - action='store', - dest='profile', - default='DEFAULT', - help='The profile in the cli/sdk config file, default is DEFAULT.') - parser.add_argument('-c', '--config', - action='store', - dest='configfile', - default='~/.oci/config', - help='The cli/sdk config file, default is ~/.oci/config.') - parser.add_argument('-d', '--data-directory', - action='store', - dest='datadir', - default='_DDDD_', - help='Root directory with data for auto test run, default is ~//data.') - parser.add_argument('-f', '--var-file', - action='store', - dest='varfilename', - default=tfvars_file, - help='filename to store the variables; the extension .tfvars.json is added automatically.') - parser._optionals.title = 'Arguments' - args = parser.parse_args() - return args - - -def _clear(): - """ - Clear screen. - - Returns - ------- - bool: True - """ - _ = call('clear' if os.name == 'posix' else 'cls') - return True - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def _is_int(string_data): - """ - Verifies if string is a valid int. - - Parameters - ---------- - string_data: str - The string to be evaluated. - - Returns - ------- - bool: True on success, false otherwise. - """ - return re.match(r"[-+]?\d+$", string_data) is not None - - -def _get_current_user(): - """ - Get the current username. - - Returns - ------- - str: the username. - """ - return getpass.getuser() - - -def _get_current_user_home(): - """ - Get the home directory of the current user. - - Returns - ------- - str: the full path of the home directory. - """ - return os.path.expanduser('~') - - -def _from_stdin(prompt, default=None): - """ - Read from stdin, if default is not set to None, some input is expected. - - Parameters - ---------- - prompt: str - The stdin prompt. - default: - Default value. - - Returns - ------- - value read - """ - while True: - return_val = input('%-40s: ' % prompt) - if bool(return_val): - return return_val - if default is not None: - return default - - -def get_configdata(profile, configfile='~/.oci/config'): - """ - Read the oci sdk/cli config file. - - Parameters - ---------- - profile: str - the config profile. - configfile: str - the path of the configfile. - Returns - ------- - dict: the config data. - """ - sdkconfigfile = configfile - if configfile.startswith('~/'): - sdkconfigfile = os.path.expanduser('~') + configfile[1:] - config = oci.config.from_file(file_location=sdkconfigfile, profile_name=profile) - return config - - -def _read_nb(prompt, min_val=1, max_val=64, default_val=1): - """ - Read an integer number from stdin. - - Parameters - ---------- - prompt: str - prompt - min_val: int - the smallest possible value. - max_val: int - the largest possible value. - default_val: int - default value if no input. - - Returns - ------- - int: the number. - """ - while 1 == 1: - read_nb = input("%s ==> " % prompt) - if not bool(read_nb): - read_nb = int(default_val) - if _is_int(read_nb): - rread_nb = int(read_nb) - if min_val <= rread_nb <= max_val: - break - print_g('Value %d out of range.' % rread_nb) - else: - print_g('Invalid input: %s' % read_nb) - _logger.debug('Value read from stdin: %d' % rread_nb) - return rread_nb - - -def _select_from(some_list, prompt, default_val=0): - """ - Select an item from a list. - - Parameters - ---------- - some_list: list - list of items. - prompt: str - prompt - default_val: int - default index value if no input. - - Returns - ------- - The list element. - """ - while 1 == 1: - selected_nb = input("%s ==> " % prompt) - if not bool(selected_nb): - selected_nb = str(default_val) - if _is_int(selected_nb): - select_index = int(selected_nb) - if 0 <= select_index < len(some_list): - break - print_g('Index %d out of range.' % select_index) - else: - print_g('Invalid input: %s' % selected_nb) - _logger.debug('Selected %s', some_list[select_index]) - return some_list[select_index] - - -def select_compartment(config_dict, prompt): - """ - Select a compartment in the tenancy. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - - prompt: str - The prompt - Returns - ------- - dict: the data of the compartment. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_compartments = oci_identity.list_compartments(config_dict['tenancy']) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for comp in oci_compartments.data: - print_g('%4d %-30s %s' % (oci_compartments.data.index(comp), comp.name, comp.id)) - return _select_from(oci_compartments.data, prompt) - - -def select_vcn(config_dict, compartment_id): - """ - Select a VCN. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the VCN - """ - try: - oci_vncclient = oci.core.VirtualNetworkClient(config_dict) - oci_vcns = oci_vncclient.list_vcns(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for vcn in oci_vcns.data: - print_g('%4d %-30s %s' % (oci_vcns.data.index(vcn), vcn.display_name, vcn.id)) - return _select_from(oci_vcns.data, 'Select VCN for instance.') - - -def select_subnet(config_dict, compartment_id, vcn_id): - """ - Select a subnet. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the subnet - """ - try: - oci_subnetclient = oci.core.VirtualNetworkClient(config_dict) - oci_subnets = oci_subnetclient.list_subnets(compartment_id, vcn_id=vcn_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for subnet in oci_subnets.data: - print_g('%4d %-30s %s' % (oci_subnets.data.index(subnet), subnet.display_name, subnet.id)) - return _select_from(oci_subnets.data, 'Select subnet instance.') - - -def select_image(config_dict, compartment_id): - """ - Select an image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the image - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - oci_images_data_all = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id).data - - # oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id, - # operating_system='Zero').data - # oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id, - # operating_system='Custom').data - # oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id, - # operating_system='Oracle Linux').data - # oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id, - # operating_system='Oracle Autonomous Linux').data - - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - oci_images_data = list() - for img in oci_images_data_all: - if 'Windows' not in img.operating_system: - oci_images_data.append(img) - for image in oci_images_data: - # print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.id)) - print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.operating_system)) - image_data = _select_from(oci_images_data, 'Select Image') - print_g(image_data, term=False) - return image_data - - -def select_availability_domain(config_dict, compartment_id): - """ - Select an availability domain. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the availability domain. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_availability_domains = oci_identity.list_availability_domains(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for domain in oci_availability_domains.data: - print_g('%4d %-30s %s' % (oci_availability_domains.data.index(domain), domain.name, domain.id)) - return _select_from(oci_availability_domains.data, 'Select availability domain.') - - -def select_shape(config_dict, image_ocid): - """ - Select a compatible shape for the image. - - Parameters - ---------- - imageid: str - The ocid pf the image. - - Returns - ------- - The shape. - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - oci_shapes = oci_imageclient.list_image_shape_compatibility_entries(image_ocid) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for shape_dict in oci_shapes.data: - print_g('%4d %-30s' % (oci_shapes.data.index(shape_dict), shape_dict.shape)) - return _select_from(oci_shapes.data, 'Select shape.') - - -def _get_display_name(): - """ - Read instance display name from stdin. - - Returns - ------- - str: the display name. - """ - return input('Instance Display Name: ') - - -def _get_authentication_method(): - """ - Determine the authentication method. - - Returns - ------- - str: the authentication method. - """ - _ = _clear() - print_g('Authentication method.\n', term=True) - auth_methods = ['ApiKey', 'InstancePrincipal'] - for authm in auth_methods: - print_g('%4d: %s' % (auth_methods.index(authm), authm)) - method = _select_from(auth_methods, 'Authentication method:') - print_g('Selected authentication method: %s\n' % method) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return method - - -def _get_remote_user(): - """ - Get the remote username. - - Returns - ------- - str: the username. - """ - _ = _clear() - print_g('Remote user.\n', term=True) - rem_user = input('\nRemote User Name: ') - print_g('Selected remote user name: %s\n' % rem_user) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return rem_user - - -def _get_http_proxy(default_proxy): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The http proxy url. - """ - new_url = input('http proxy url\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_https_proxy(default_proxy): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The https proxy url. - """ - new_url = input('https proxy url\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_no_proxy(default_proxy): - """ - Get the no proxy list. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The https proxy url. - """ - new_url = input('no proxy\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_log_file(default_log_file): - """ - Get the log file path. - - Parameters - ---------- - default_log_file: str - The default path. - - Returns - ------- - The path tot the log file. - """ - _ = _clear() - print_g('Log file path.\n', term=True) - new_log_file = input('log file path\n [%s] (ENTER to accept default):' % default_log_file) - print_g('Selected log file path: %s\n' % new_log_file) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return new_log_file - - -def _get_dns_search_domain(): - """ - Get the dns search domain. - - Returns - ------- - str: The dns search domain, default is retrieved from /etc/resolv.conf. - """ - resolv_file = '/etc/resolv.conf' - search_domain = 'whocares' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'search' in rf_line: - search_domain = rf_line.split()[1] - break - return search_domain - - -def _get_dns_server_ip(): - """ - Get the dns server ipv4 - - Returns - ------- - str: The dns server ipv4 address., default is retrieved from /etc/resolv.conf. - """ - resolv_file = '/etc/resolv.conf' - nameserver = '8.8.8.8' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'nameserver' in rf_line: - nameserver = rf_line.split()[1] - break - return nameserver - - -def get_generic_data(): - """ - Get generic variables. - - Parameters - ---------- - gendata: str - path to generic data directory. - - Returns - ------- - dict: the generic variables. - """ - gen_data = { - # 'instance_display_name': _get_display_name(), - 'auth': _get_authentication_method(), - 'remote_user': _get_remote_user(), - # 'http_proxy_url': _get_http_proxy(default_values['http_proxy_url']), - # 'https_proxy_url': _get_https_proxy(default_values['https_proxy_url']), - # 'http_no_proxy': _get_no_proxy(default_values['http_no_proxy']), - 'log_file_path': _get_log_file(default_values['log_file_path']), - # 'dns_search_domains': _get_dns_search_domain(), - # 'dns_server_ip': _get_dns_server_ip() - } - return gen_data - - -def create_dir(dirname): - """ - Create a directory, make a backup copy if already exists. - - Parameters - ---------- - dirname: str - Full path - - Returns - ------- - bool: True on success, false otherwise. - """ - try: - if os.path.exists(dirname): - bck_name = dirname + '_%s' % datetime.now().strftime('%Y%m%d_%H%M') - os.rename(dirname, bck_name) - print_g('Renamed %s to %s' % (dirname, bck_name), term=False) - os.makedirs(dirname) - print_g('Created %s' % dirname) - except OSError as e: - if e.errno != errno.EEXIST: - print_g('Failed to create %s' % dirname, term=False) - return False - print_g('%s already exists, might cause problems.' % dirname, term=False) - return True - - -def copy_dir(src, dest): - """ - Copy a directory recursively. - - Parameters - ---------- - src:str - Source dir - dest: str - Destination dir - - Returns - ------- - bool: True on success, False otherwise - """ - try: - if os.path.exists(dest): - shutil.rmtree(dest) - shutil.copytree(src, dest, symlinks=False) - print_g('Copied %s to %s' % (src, dest)) - except Exception as e: - _logger.error('Failed to copy %s to %s: %s', src, dest, str(e)) - return False - return True - - -def write_bash(fn, cmd): - """ - Write a command to the script file fn. - - Parameters - ---------- - fn: str - Full path of the script file. - cmd: str - The string. - - Returns - ------- - bool: True or False - """ - try: - if not os.path.exists(fn): - with open(fn, 'w') as fd: - fd.write('#!/bin/bash\n') - fd.flush() - os.chmod(fn, 0o755) - with open(fn, 'a') as fd: - fd.write('%s\n' % cmd) - fd.flush() - fd.write('RETVAL=${?}\n') - fd.flush() - fd.write('if [ $RETVAL -ne 0 ]; then\n') - fd.flush() - fd.write(' echo "%s failed"\n' % cmd) - fd.flush() - fd.write(' exit $RETVAL\n') - fd.flush() - fd.write(' echo "%s succeeded"\n' % cmd) - fd.write('fi\n') - fd.flush() - return True - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - return False - - -def init_struct(instance_name): - """ - Initialise config struct. - - Parameters - ---------- - instance_name: str - The instance display name. - - Returns - ------- - dict: the config structure. - """ - # - # exec dir - data = dict() - exec_dir = inspect.getfile(inspect.currentframe()) - data['instance_display_name'] = instance_name - data['exec_dir'] = os.path.dirname(exec_dir) - data['base_exec_dir'] = os.path.dirname(exec_dir) - return data - - -def get_user_data(data): - """ - Collect operator data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - data['operator'] = _get_current_user() - data['operator_home'] = _get_current_user_home() - print_g('Username: %s' % data['operator']) - print_g('Home: %s' % data['operator_home']) - return data - - -def create_directories(data, args): - """ - Create directories for scripts. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - def_base_dir = data['operator_home'] + '/' + default_instance_dir - instance_display_name = data['instance_display_name'] - data['def_instance_dir'] = def_base_dir + '/' + instance_display_name - data['def_data_dir'] = def_base_dir + '/' + instance_display_name + '/data' - data['base_instance_dir'] = def_base_dir + '/' + instance_display_name + '/base_instance' - data['def_tf_scripts_dir'] = def_base_dir + '/' + instance_display_name + '/tf_scripts' - data['def_sh_scripts_dir'] = def_base_dir + '/' + instance_display_name + '/sh_scripts' - if args.datadir != '_DDDD_': - data['def_data_dir'] = args.datadir + '/data' - data['def_tf_scripts_dir'] = args.datadir + '/tf_scripts' - data['def_sh_scripts_dir'] = args.datadir + '/sh_scripts' - data['base_instance_dir'] = args.datadir + '/base_instance' - print_g('Default instance dir %s' % data['def_instance_dir']) - print_g('Default data dir %s' % data['def_data_dir']) - print_g('Base instance dir %s' % data['base_instance_dir']) - print_g('Default tf_scripts dir %s' % data['def_tf_scripts_dir']) - print_g('Default sh_scripts dir %s' % data['def_sh_scripts_dir']) - if not create_dir(data['def_instance_dir']): - sys.exit(1) - if not create_dir(data['def_tf_scripts_dir']): - sys.exit(1) - if not create_dir(data['def_sh_scripts_dir']): - sys.exit(1) - if not create_dir(data['def_data_dir']): - sys.exit(1) - if not create_dir(data['base_instance_dir']): - sys.exit(1) - return data - - -def copy_scripts(data): - """ - Copy the tf scripts in place. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - # if not copy_dir(operator_home + '/create_instance/base_instance', base_instance_dir): - if not copy_dir(os.path.join(operator_home, create_instance_source, 'base_instance'), base_instance_dir): - print_g('Failed to copy %s' % base_instance_dir) - sys.exit(1) - def_tf_scripts_dir = data['def_tf_scripts_dir'] - # if not copy_dir(operator_home + '/create_instance/tf_scripts', def_tf_scripts_dir): - if not copy_dir(os.path.join(operator_home, create_instance_source, 'tf_scripts'), def_tf_scripts_dir): - print_g('Failed to copy %s' % def_tf_scripts_dir) - sys.exit(1) - def_sh_scripts_dir = data['def_sh_scripts_dir'] - # if not copy_dir(operator_home + '/create_instance/sh_scripts', def_sh_scripts_dir): - if not copy_dir(os.path.join(operator_home, create_instance_source, 'sh_scripts'), def_sh_scripts_dir): - print_g('Failed to copy %s' % def_sh_scripts_dir) - sys.exit(1) - return True - - -def update_public_ip(data, public_ip): - """ - Update the script for public or private ip. - - Parameters - ---------- - data: dict - The configuration data. - public_ip: bool - If True set for public ip. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['def_tf_scripts_dir'] - api_key = tf_scripts_dir + '/api_key.tf' - rsa_key = tf_scripts_dir + '/rsa_key.tf' - rsa_pub_key = tf_scripts_dir + '/rsa_pub_key.tf' - output_b = base_instance_dir + '/output.tf' - output_t = tf_scripts_dir + '/output.tf' - main_b = base_instance_dir + '/main.tf' - iptype = 'public' if public_ip else 'private' - print_g('operator home %s' % operator_home, term=False) - print_g('base instance dir %s' % base_instance_dir, term=False) - print_g('api key %s' % api_key, term=False) - print_g('rsa key %s' % rsa_key, term=False) - print_g('rsa_pub key %s' % rsa_pub_key, term=False) - print_g('output b %s' % output_b, term=False) - print_g('main b %s' % main_b, term=False) - print_g('iptype %s' % iptype, term=False) - - # - # tf_scripts/api_key - with open(api_key, 'r+') as fx: - api_text = fx.read() - api_text = re.sub('XXXX', iptype, api_text) - fx.seek(0) - fx.write(api_text) - print_g('api text: %s' % api_text, term=False) - fx.truncate() - # - # tf_scripts/rsa_key - with open(rsa_key, 'r+') as fx: - rsa_text = fx.read() - rsa_text = re.sub('XXXX', iptype, rsa_text) - fx.seek(0) - fx.write(rsa_text) - print_g('api text: %s' % rsa_text, term=False) - fx.truncate() - # - # tf_scripts/rsa_pub_key - with open(rsa_pub_key, 'r+') as fx: - rsa_pub_text = fx.read() - rsa_pub_text = re.sub('XXXX', iptype, rsa_pub_text) - fx.seek(0) - fx.write(rsa_pub_text) - print_g('api text: %s' % rsa_pub_text, term=False) - fx.truncate() - # - # base_instance/main - with open(main_b, 'r+') as fx: - main_text = fx.read() - main_text = re.sub('XXXX', iptype, main_text) - fx.seek(0) - fx.write(main_text) - print_g('main text: %s' % main_text, term=False) - fx.truncate() - # - # output public ip if one available - if public_ip: - # - # base_instance/output - with open(output_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//XXXX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # tf_scripts/output - with open(output_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//XXXX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def update_flex(data): - """ - Update the terraform scripts for usage with Flex shapes. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - bool: True - """ - # - # tf_scripts/main.tf - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['def_tf_scripts_dir'] - main_t = tf_scripts_dir + '/main.tf' - main_b = base_instance_dir + '/main.tf' - with open(main_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//YYYY', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # base_instance/main.tf - with open(main_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//YYYY', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def get_oci_config(data, args): - """ - Get the oci configuration. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - cfg_dict = get_configdata(args.profile, args.configfile) - print_g('Configuration') - for k, v in cfg_dict.items(): - print_g('%40s: %s' % (k, v)) - data['oci_config'] = cfg_dict - return data - - -def get_instance_compartment(data): - """ - Get the compartment data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Compartment.\n', term=True) - instance_compartment = select_compartment(data['oci_config'], "Select compartment for the instance.") - print_g(instance_compartment, term=False) - print_g('Selected compartment: %s\n' % instance_compartment.name) - data['compartment'] = instance_compartment - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_availability_domain(data): - """ - Get the availablility domain data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Availability domain.\n', term=True) - availability_domain = select_availability_domain(data['oci_config'], data['compartment'].id) - print_g(availability_domain, term=False) - print_g('Selected availability domain: %s\n' % availability_domain.name) - data['availability_domain'] = availability_domain.name - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_network_compartment(data): - """ - Get the network compartment. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Network compartment.\n', term=True) - network_compartment = select_compartment(data['oci_config'], "Select compartment for the network.") - print_g(network_compartment, term=False) - print_g('Selected network compartment: %s\n' % network_compartment.name) - data['network_compartment'] = network_compartment - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_vcn(data): - """ - Get the VCN data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Virtual cloud network.\n', term=True) - vcn = select_vcn(data['oci_config'], data['network_compartment'].id) - data['vcn'] = vcn - print_g(vcn, term=False) - print_g('Selected VCN: %s\n' % vcn.display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_subnet(data): - """ - Get the subnet data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Subnet.\n', term=True) - subnet = select_subnet(data['oci_config'], data['network_compartment'].id, vcn_id=data['vcn'].id) - data['subnet'] = subnet - print_g(subnet, term=False) - print_g('Selected subnet: %s\n' % subnet.display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_public_ip(): - """ - Request for public ip. - - Returns - ------- - bool: true or false. - """ - _ = _clear() - return True if _read_yn('Assign a public IPv4 address?') else False - - -def get_image(data): - """ - Get the image data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Image.\n', term=True) - data['image'] = select_image(data['oci_config'], data['compartment'].id) - print_g(data['image'].id, term=False) - print_g('Selected image: %s\n' % data['image'].display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_shape(data): - """ - Get the instance shape. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Shape.\n', term=True) - data['shape'] = select_shape(data['oci_config'], data['image'].id) - print_g(data['shape'], term=False) - print_g('Selected shape: %s\n' % data['shape'].shape) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_flex_data(data): - """ - Get the Flex shape data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Flex shape data.\n', term=True) - # - # memory - data['instance_flex_memory_in_gbs'] = _read_nb('Memory in GB', default_val=4, max_val=256) - print_g(data['instance_flex_memory_in_gbs'], term=False) - print_g('Selected memory size: %dGB' % data['instance_flex_memory_in_gbs']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - # cpus - data['instance_flex_ocpus'] = _read_nb('Number of OCPUs', default_val=2, max_val=64) - print_g(data['instance_flex_ocpus'], term=False) - print_g('Selected number of OCPUs: %d' % data['instance_flex_ocpus']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - return data - - -def get_boot_volume_size(data): - """ - Get the size of the boot volume in GigaBytes. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Boot Volume Size in GigaBytes', term=True) - data['boot_volume_size_in_gbs'] = _read_nb('Boot Volume Size', default_val=51, max_val=2048) - print_g(data['boot_volume_size_in_gbs'], term=False) - print_g('Selected boot volume size: %dGB' % data['boot_volume_size_in_gbs']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - return data - - -def print_config_data(xx): - """ - Print dict. - - Parameters - ---------- - xx: dict - The data to print. - - Returns - ------- - No return value. - """ - for k,v in xx.items(): - print('%30s: %s' % (k,v)) - - -def write_scripts(data): - """ - Write the scripts. - Parameters - ---------- - data: the configuration data. - - Returns - ------- - No return value. - """ - def_log_dir = data['def_instance_dir'] - print_g('Run\n' - 'terraform -chdir=%s init\n' - 'terraform -chdir=%s validate\n' - 'terraform -chdir=%s plan -var-file=%s\n' - 'terraform -chdir=%s apply -var-file=%s -auto-approve | tee %s/creation.log\n' - 'terraform -chdir=%s destroy -var-file=%s -auto-approve' - % (data['def_tf_scripts_dir'], - data['def_tf_scripts_dir'], - data['def_tf_scripts_dir'], data['tfvarsfile'], - data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir, - data['def_tf_scripts_dir'], data['tfvarsfile'])) - create_script = data['def_instance_dir'] + '/create' - if not write_bash(create_script, 'terraform -chdir=%s init' - % data['def_tf_scripts_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s validate' - % data['def_tf_scripts_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s plan --var-file=%s' - % (data['def_tf_scripts_dir'], data['tfvarsfile'])): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s apply --var-file=%s -auto-approve | tee %s/creation.log' - % (data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir)): - sys.exit(1) - destroy_script = data['def_instance_dir'] + '/destroy' - if not write_bash(destroy_script, 'terraform -chdir=%s destroy --var-file=%s -auto-approve | tee %s/destruction.log' - % (data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir)): - sys.exit(1) - print_g('\nor\n%s\n%s' % (create_script, destroy_script)) - - -class autotesttfvars: - """ - Manipulate the tfvar.json file. - """ - def __init__(self, tfvars_file): - """ - Initialise. - - Parameters - ---------- - tfvars_file: str - Full path of the tfvar.json file. - # sdkconfig: dict - # Contents of the sdk config file. - """ - self.json_file = tfvars_file - # self.sdkconfig = sdkconfig - try: - with open(self.json_file, 'rb') as tfvj: - self.jsondata = json.load(tfvj) - except Exception as e: - # - # Failed to read variable def file, falling back to idle defaults. - print_g('Failed to read %s, creating default' % self.json_file) - self.jsondata = default_values - - def __enter__(self): - return self - - def __exit__(self, xtype, value, traceback): - try: - with open(self.json_file, 'w') as tfvj: - json.dump(self.jsondata, tfvj, indent=4) - return True - except Exception as e: - raise Exception('Failed to write %s:' % self.json_file) from e - - def update_json_with_config(self, sdk_config): - """ - Update tf.json file with .oci/config data. - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g('\nCollecting data from sdk config file:') - self.jsondata['user_ocid'] = sdk_config['user'] - print_g('user ocid: %s' % sdk_config['user']) - self.jsondata['fingerprint'] = sdk_config['fingerprint'] - print_g('fingerprint %s' % sdk_config['fingerprint']) - self.jsondata['oci_private_key'] = sdk_config['key_file'] - print_g('oci_private_key: %s' % sdk_config['key_file']) - self.jsondata['tenancy_ocid'] = sdk_config['tenancy'] - print_g('tenancy_ocid: %s' % sdk_config['tenancy']) - self.jsondata['region'] = sdk_config['region'] - print_g('region: %s' % sdk_config['region']) - if _read_yn('Agree?', default_yn=True): - return True - return False - - def update_user(self, display_name): - """ - Update tf.json file with user related data. - - Parameters - ---------- - display_name: str - The instance display name - - Returns - ------- - bool: True on success, False otherwise. - """ - # - # os user data - current_user = _get_current_user() - if bool(self.jsondata['os_user']): - if _read_yn('\nReplace %s by %s' % (self.jsondata['os_user'], current_user), default_yn=True): - self.jsondata['os_user'] = current_user - else: - self.jsondata['os_user'] = _from_stdin('os user', default=current_user) - - current_user_home = _get_current_user_home() - if bool(self.jsondata['os_user_home']): - if _read_yn('Replace %s by %s' % (self.jsondata['os_user_home'], current_user_home), default_yn=True): - self.jsondata['os_user_home'] = current_user_home - else: - self.jsondata['os_user_home'] = _from_stdin('os user home', default=current_user_home) - # - # ssh keys - pub_key = current_user_home + '/.ssh/id_rsa.pub' - if bool(self.jsondata['ssh_public_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_public_key'], pub_key), default_yn=True): - self.jsondata["ssh_public_key"] = pub_key - else: - self.jsondata['ssh_publid_key'] = _from_stdin('ssh public key', default=pub_key) - priv_key = current_user_home + '/.ssh/id_rsa' - if bool(self.jsondata['ssh_private_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_private_key'], priv_key), default_yn=True): - self.jsondata["ssh_private_key"] = priv_key - else: - self.jsondata['ssh_private_key'] = _from_stdin('ssh private key', default=priv_key) - # - # initial script - # self.jsondata['initial_script_path'] = self.jsondata['os_user_home'] \ - # + '/' \ - # + default_instance_dir \ - # + '/' \ - # + display_name \ - # + '/sh_scripts/initial_config.sh' - self.jsondata['initial_script_path'] = os.path.join(self.jsondata['os_user_home'], - default_instance_dir, - display_name, - 'sh_scripts', - 'initial_config.sh') - # - # ip V4 address - thisipv4 = socket.gethostbyname(socket.gethostname()) - if bool(self.jsondata['server_ip']): - if _read_yn('Replace %s by %s' % (self.jsondata['server_ip'], thisipv4), default_yn=True): - self.jsondata['server_ip'] = thisipv4 - else: - self.jsondata['server_ip'] = _from_stdin('server ip address', default=thisipv4) - return True - - def update_image(self, image_data): - """ - Update tf.json file with image related data. - - Parameters - ---------- - image_data: dict - The image data - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g(image_data) - for k, v in image_data.items(): - print_g('%30s %s' % (k, v)) - self.jsondata[k] = v - - return True - - def update_varia(self, variadata): - """ - Update various data. - - Parameters - ---------- - variadata: dict - The various data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in variadata.items(): - print_g('%30s %s' % (var_key, var_val)) - self.jsondata[var_key] = var_val - return True - - def update_gen_data(self, gendata): - """ - Update tf.json with generic data. - - Parameters - ---------- - gendata: dict - The generic data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in gendata.items(): - self.jsondata[var_key] = var_val - return True - - -def main(): - """ - Configure auto tests. - - Returns - ------- - int: 0 on success, raises exception on failure. - """ - # - # locale - os.environ['LC_ALL'] = "%s" % lc_all - # - # parse the commandline - args = parse_args() - # - # clear - _ = _clear() - # - # instance name to create - instance_display_name = args.display_name if args.display_name is not None else _get_display_name() - # - # exec dir - config_data = init_struct(instance_display_name) - # - # initialise logging - logging.basicConfig(filename=default_log + instance_display_name + '.log', - level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s (%(module)s:%(lineno)s) - %(message)s') - # - # show initial data - print_g('Display name: %s' % instance_display_name) - print_g('exec dir: %s' % config_data['exec_dir'], term=False) - print_g('base exec dir: %s' % config_data['base_exec_dir'], term=False) - # - # current user - config_data = get_user_data(config_data) - # - # initialise data structure - image_data = dict() - # - # create directories - config_data = create_directories(config_data, args) - # - # copy the scripts in place. - _ = copy_scripts(config_data) - # - # tf variable file path - config_data['tfvarsfile'] = config_data['def_data_dir'] + '/' + args.varfilename + '.tfvars.json' - print_g('tfvars file: %s' % config_data['tfvarsfile']) - # - # Get configuration data from config file. - config_data = get_oci_config(config_data, args) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - _ = _clear() - # - # compose var file. - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_json_with_config(config_data['oci_config']) - print_g('Updated variables with config data', term=True) - _ = atfv.update_user(instance_display_name) - print_g('Updated variables with operator data', term=True) - except Exception as e: - print_g('***ERROR*** %s' % str(e), term=True) - # - # Instance compartment - config_data = get_instance_compartment(config_data) - image_data['compartment_ocid'] = config_data['compartment'].id - # _ = _clear() - # - # Availability domain - config_data = get_availability_domain(config_data) - image_data['availability_domain'] = config_data['availability_domain'] - # - # Network compartment - config_data = get_network_compartment(config_data) - # - # Virtual Cloud Network - config_data = get_vcn(config_data) - # - # Subnets - config_data = get_subnet(config_data) - image_data['subnet_ocid'] = config_data['subnet'].id - # - # Public ip - # Public ip - image_data['assign_public_ip'] = get_public_ip() - # - # update public ip - _ = update_public_ip(config_data, image_data['assign_public_ip']) - # - # Type - image_data['source_type'] = 'image' - # - # Images - config_data = get_image(config_data) - image_data['source_ocid'] = config_data['image'].id - # - # Shape - config_data = get_shape(config_data) - image_data['shape'] = config_data['shape'].shape - # - # Boot volume size - config_data = get_boot_volume_size(config_data) - image_data['boot_volume_size_in_gbs'] = config_data['boot_volume_size_in_gbs'] - # - # is shape Flex? - if bool(re.search('Flex', image_data['shape'])): - config_data = get_flex_data(config_data) - image_data['instance_flex_memory_in_gbs'] = config_data['instance_flex_memory_in_gbs'] - image_data['instance_flex_ocpus'] = config_data['instance_flex_ocpus'] - _ = update_flex(config_data) - # - # get generic variables - gen_data = get_generic_data() - gen_data['instance_display_name'] = instance_display_name - # - # various data - varia_data = {'vnic_display_name': instance_display_name} - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_varia(varia_data) - print_g('Updated various data.') - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - # - # update tfvars file - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_image(image_data) - print_g('Updated variables with image data.') - _ = atfv.update_gen_data(gen_data) - print_g('Updated variables with generic data.') - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - # - print_g('Wrote configuration to %s' % config_data['tfvarsfile']) - # - write_scripts(config_data) - sys.exit(0) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/provisioning/gen_instance/gen_scripts/initial_config.sh b/tools/provisioning/gen_instance/gen_scripts/initial_config.sh deleted file mode 100644 index 649a4898..00000000 --- a/tools/provisioning/gen_instance/gen_scripts/initial_config.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/bash -x -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http:/oss.oracle.com/licenses/upl. - -RPM=$(command -v rpm) -GREP=$(command -v grep) -FIND=$(command -v find) -SED=$(command -v sed) -MKDIR=$(command -v mkdir) -CHMOD=$(command -v chmod) -DNF=dnf -YUM=yum -SYSTEMCTL=$(command -v systemctl) -SUDO=$(command -v sudo) -INITIALLOG=/logs/initial.log -REDHATRELEASE=/etc/redhat-release -OSRELEASE=/etc/os-release -RMF="rm -rf" -HTTP_PROXY=http://www-proxy.us.oracle.com:80 -HTTPS_PROXY=http://www-proxy.us.oracle.com:80 -NO_PROXY=69.254.169.254,.oracle.com,osdevelopm1lhr.oraclevcn.com -SHEBANG='#!/bin/bash' -TAILOCILOG="/usr/local/sbin/tailocilog" - -${SUDO} --login mkdir -p /logs -${SUDO} --login mkdir /logs -${SUDO} --login chmod 777 /logs - -if [ -f "${OSRELEASE}" ]; then - OSNAME=$(grep "^NAME=" "${OSRELEASE}"| cut -d'=' -f2 | tr -d '"') - OSPRETTYNAME=$(grep "^PRETTY_NAME=" "${OSRELEASE}"| cut -d'=' -f2 | tr -d '"') - OSVERSION=$(grep "^VERSION_ID=" "${OSRELEASE}"| cut -d'=' -f2 | tr -d '"') - OSTYPE=$(grep "^ID=" "${OSRELEASE}"| cut -d'=' -f2 | tr -d '"') -else - OSNAME=none - OSPRETTYNAME=none - OSVERSION=0 - OSTYPE=none -fi - -${SUDO} --login echo ${OSNAME} > ${INITIALLOG} 2>&1 -${SUDO} --login echo ${OSPRETTYNAME} >> ${INITIALLOG} 2>&1 -${SUDO} --login echo ${OSTYPE} >> ${INITIALLOG} 2>&1 -${SUDO} --login echo ${OSVERSION} >> ${INITIALLOG} 2>&1 - -# ${SUDO} --login echo "export no_proxy=${NO_PROXY}" >> /etc/bash.bashrc -# ${SUDO} --login echo "export http_proxy=${HTTP_PROXY}" >> /etc/bash.bashrc -# ${SUDO} --login echo "export https_proxy=${HTTPS_PROXY}" >> /etc/bash.bashrc - -if [ "${OSTYPE}" = "ol" ] || [ "${OSTYPE}" = "fedora" ] || [ "${OSTYPE}" = "redhat" ]; then - if ! command -v dnf; then - installrpm=$(command -v yum) - ${SUDO} --login "${installrpm}"-config-manager --enablerepo ol${OSVERSION}_developer >> ${INITIALLOG} 2>&1 - else - installrpm=$(command -v dnf) - ${SUDO} --login "${installrpm}" config-manager --set-enabled ol${OSVERSION}_developer >> ${INITIALLOG} 2>&1 - fi - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - ${SUDO} --login "${installrpm}" repolist >> ${INITIALLOG} 2>&1 - RET=${?} - done - ${SUDO} --login "${installrpm}" --assumeyes install tree strace tmux iotop psmisc net-tools git traceroute >> ${INITIALLOG} 2>&1 - RPMLIST=("python3-pip" "python3-setuptools" "python3-wheel" "python3-netaddr" "python3-daemon" "python3-sdnotify" ) - for rpmpack in "${RPMLIST[@]}" - do - RET=1 - # while [ ${RET} -ne 0 ] - # do - sleep 5 - echo "${rpmpack}" - ${SUDO} --login "${installrpm}" --assumeyes install "${rpmpack}" >> ${INITIALLOG} 2>&1 - RET=${?} - # done - done - ${SUDO} --login "${installrpm}" --assumeyes install git python3-pip python3-setuptools python3-wheel python3-netaddr python3-daemon python3-sdnotify traceroute >> ${INITIALLOG} 2>&1 -elif [ "${OSTYPE}" = "debian" ] || [ "${OSTYPE}" = "ubuntu" ]; then - installdeb=$(command -v apt) - installdebprox="https_proxy=${HTTP_PROXY} http_proxy=${HTTP_PROXY} ${installdeb}" - APTLIST=( "tree" "strace" "tmux" "iotop" "psmisc" "net-tools" "git" "python3-pip" "python3-setuptools" "python3-wheel" "python3-netaddr" "python3-daemon" "python3-sdnotify" "traceroute") - PIPLIST=( "cryptography" "oci") - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - ${SUDO} --login "${installdebprox}" update >> ${INITIALLOG} 2>&1 - RET=${?} - done - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - ${SUDO} --login "${installdebprox}" upgrade --yes >> ${INITIALLOG} 2>&1 - RET=${?} - done - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - ${SUDO} --login "${installdebprox}" update >> ${INITIALLOG} 2>&1 - RET=${?} - done - for aptpack in "${APTLIST[@]}" - do - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - echo "${aptpack}" - ${SUDO} --login "${installdebprox}" install "${aptpack}" --yes >> ${INITIALLOG} 2>&1 - RET=${?} - done - done - - pip3=pip3 - pip3prox="https_proxy=${HTTP_PROXY} http_proxy=${HTTP_PROXY} ${pip3}" - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - ${SUDO} --login "${pip3prox}" install --upgrade pip >> ${INITIALLOG} 2>&1 - RET=${?} - done - - for pippack in "${PIPLIST[@]}" - do - RET=1 - while [ ${RET} -ne 0 ] - do - sleep 5 - ${SUDO} --login "${pip3prox}" install "${pippack}" >> ${INITIALLOG} 2>&1 - RET=${?} - done - done -else - ${SUDO} --login echo "not a supported os" >> ${INITIALLOG} 2>&1 -fi - -# -# excluding the kernel can cause the install failing -# ${SUDO} --login ${installrpm} --assumeyes update --exclude=kernel*,oci-utils* >> ${INITIALLOG} 2>&1 - -${SUDO} -i < ${TAILOCILOG} -echo "rm -f /var/tmp/oci-utils.log ; touch /var/tmp/oci-utils.log ; clear; tail -f /var/tmp/oci-utils.log" >> ${TAILOCILOG} -EOF -${CHMOD} 755 ${TAILOCILOG} diff --git a/tools/provisioning/gen_instance/tf_scripts/api_key.tf b/tools/provisioning/gen_instance/tf_scripts/api_key.tf deleted file mode 100644 index 75ddeb77..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/api_key.tf +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_sdk_config" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.oci_private_key - destination = "/tmp/oci_private_key.pem" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.oci", - "/bin/sudo --preserve-env cp /tmp/oci_private_key.pem /root/.oci/$(basename ${var.oci_private_key})", - "/bin/sudo --preserve-env echo [DEFAULT] > /tmp/config", - "/bin/sudo --preserve-env echo user=${var.user_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo fingerprint=${var.fingerprint} >> /tmp/config", - "/bin/sudo --preserve-env echo key_file=/root/.oci/$(basename ${var.oci_private_key}) >> /tmp/config", - "/bin/sudo --preserve-env echo tenancy=${var.tenancy_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo region=${var.region} >> /tmp/config", - "/bin/sudo cp /tmp/config /root/.oci/config", - "/bin/sudo chmod -R 600 /root/.oci/", - "/bin/sudo chmod 700 /root/.oci", - "/bin/sudo --preserve-env mkdir -p /home/${var.remote_user}/.oci", - "/bin/sudo cp /tmp/config /home/${var.remote_user}/.oci/config", - "/bin/sudo --preserve-env chown -R ${var.remote_user}:${var.remote_user} /home/${var.remote_user}/.oci", - "/bin/sudo chmod -R 600 /home/${var.remote_user}/.oci/", - "/bin/sudo chmod 700 /home/${var.remote_user}/.oci" - ] - } -} diff --git a/tools/provisioning/gen_instance/tf_scripts/data.tf b/tools/provisioning/gen_instance/tf_scripts/data.tf deleted file mode 100644 index 8130d272..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/data.tf +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} - diff --git a/tools/provisioning/gen_instance/tf_scripts/main.tf b/tools/provisioning/gen_instance/tf_scripts/main.tf deleted file mode 100644 index 47361ae2..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/main.tf +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//YYYYvariable "instance_flex_memory_in_gbs" { -//YYYY description = "instance memorry size in GB." -//YYYY type = number -//YYYY} - -//YYYYvariable "instance_flex_ocpus" { -//YYYY description = "amount of instance ocpus." -//YYYY type = number -//YYYY} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "boot_volume_size_in_gbs" { - description = "size of boot volume in GBits" - type = number -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "initial_script_path" { - description = "path to initial bash script" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape -//YYYY instance_flex_memory_in_gbs = var.instance_flex_memory_in_gbs -//YYYY instance_flex_ocpus = var.instance_flex_ocpus - source_ocid = var.source_ocid - source_type = var.source_type - boot_volume_size_in_gbs = var.boot_volume_size_in_gbs - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path - initial_script_path = var.initial_script_path -} diff --git a/tools/provisioning/gen_instance/tf_scripts/output.tf b/tools/provisioning/gen_instance/tf_scripts/output.tf deleted file mode 100644 index 2f326d2b..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/output.tf +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - value = module.base_instance.instance_private_ip -} - -//XXXXoutput "instance_public_ip" { -//XXXX value = module.base_instance.instance_public_ip -//XXXX} - -output "boot_volume_ocid" { - value = module.base_instance.boot_volume_ocid -} - -output "instance_ocid" { - value = module.base_instance.instance_ocid -} \ No newline at end of file diff --git a/tools/provisioning/gen_instance/tf_scripts/rsa_key.tf b/tools/provisioning/gen_instance/tf_scripts/rsa_key.tf deleted file mode 100644 index b75eca2d..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/rsa_key.tf +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_private_key" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.ssh_private_key - destination = "/tmp/id_rsa" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa /root/.ssh/id_rsa", - "/bin/sudo chmod -R 600 /root/.ssh/", - "/bin/sudo chmod 700 /root/.ssh", - "/bin/sudo --preserve-env mkdir -p /home/${var.remote_user}/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa /home/${var.remote_user}/.ssh/id_rsa", - "/bin/sudo --preserve-env chown -R ${var.remote_user}:${var.remote_user} /home/${var.remote_user}/.ssh", - "/bin/sudo chmod -R 600 /home/${var.remote_user}/.ssh/", - "/bin/sudo chmod 700 /home/${var.remote_user}/.ssh" - ] - } -} diff --git a/tools/provisioning/gen_instance/tf_scripts/rsa_pub_key.tf b/tools/provisioning/gen_instance/tf_scripts/rsa_pub_key.tf deleted file mode 100644 index c09f5b63..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/rsa_pub_key.tf +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_public_key" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.ssh_public_key - destination = "/tmp/id_rsa.pub" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa.pub /root/.ssh/id_rsa.pub", - "/bin/sudo chmod -R 600 /root/.ssh/", - "/bin/sudo chmod 700 /root/.ssh", - "/bin/sudo --preserve-env mkdir -p /home/${var.remote_user}/.ssh", - "/bin/sudo --preserve-env cp /tmp/id_rsa.pub /home/${var.remote_user}/.ssh/id_rsa.pub", - "/bin/sudo --preserve-env chown -R ${var.remote_user}:${var.remote_user} /home/${var.remote_user}/.ssh", - "/bin/sudo chmod -R 600 /home/${var.remote_user}/.ssh/", - "/bin/sudo chmod 700 /home/${var.remote_user}/.ssh/" - ] - } -} diff --git a/tools/provisioning/gen_instance/tf_scripts/version.tf b/tools/provisioning/gen_instance/tf_scripts/version.tf deleted file mode 100644 index 3d2fdf15..00000000 --- a/tools/provisioning/gen_instance/tf_scripts/version.tf +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} \ No newline at end of file diff --git a/tools/provisioning/kvm_instance/Makefile b/tools/provisioning/kvm_instance/Makefile deleted file mode 100644 index f2fd2c78..00000000 --- a/tools/provisioning/kvm_instance/Makefile +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# makefile for creating an instance in OCI -# -# -# -# proxy -# -export no_proxy=169.254.169.254,.oraclecloud.com -# -CREATEKVMINSTANCEPY=bin/create_kvm_instance.py -CREATEKVMINSTANCESH=bin/create_kvm_instance -BINARIES=$(CREATEKVMINSTANCESH) $(CREATEKVMINSTANCEPY) - -BASEDATATF=base_instance/data.tf -BASEMAINTF=base_instance/main.tf -BASEOUTPUTTF=base_instance/output.tf -BASES=$(BASEDATATF) $(BASEMAINTF) $(BASEOUTPUTTF) - -TFAPITF=tf_scripts/api_key.tf -TFDATATF=tf_scripts/data.tf -TFMAINTF=tf_scripts/main.tf -TFVERSION=tf_scripts/version.tf -TFOUTPUTTF=tf_scripts/output.tf -TFSCRIPTS=$(TFAPITF) $(TFDATATF) $(TFMAINTF) $(TFVERSION) $(TFOUTPUTTF) - -INITIALSCRIPT=gen_scripts/initial_config.sh -SHSCRIPTS=$(INITIALSCRIPT) -# -# files involved -FILELIST=Makefile README.md $(BINARIES) $(BASES) $(TFSCRIPTS) $(SHSCRIPTS) -# -TARGET=create_kvm_instance -VERSION=0.1_Dec_09_2021 -WRITE=@echo -CREATETAR=tar -cjvf -EXPANDTAR=tar -xjvf -MKDIR=-mkdir -p -RMFORCE=rm -rf -DELETE=rm -f -INSTALL=install --mode=755 -COPYA=cp -a -SUDO=sudo -# -# destinations -HOMEBINS=$(HOME)/bin -HOMEBASES=$(HOME)/$(TARGET)/base_instance -HOMETFSCRIPTS=$(HOME)/$(TARGET)/tf_scripts -HOMESHSCRIPTS=$(HOME)/$(TARGET)/sh_scripts -# -# tarball name -TARBALL=$(TARGET).$(VERSION).bz -# help -# -.PHONY: help -help: - $(WRITE) "help info:" - $(WRITE) " make help" - $(WRITE) " make show_version" - $(WRITE) " make tarball" - $(WRITE) " make install" - $(WRITE) " make uninstall" - -# -# version info -.PHONY: showversion -show_version: - $(WRITE) "version of $(TARGET) source is $(VERSION)" -# -# create tarball -tarball: - $(CREATETAR) $(TARBALL) $(FILELIST) -# -# create directories -bindir: - $(MKDIR) $(HOMEBINS) - -basedir: - $(MKDIR) $(HOMEBASES) - -tfscriptdir: - $(MKDIR) $(HOMETFSCRIPTS) - -shscriptdir: - $(MKDIR) $(HOMESHSCRIPTS) -# -# lists -$(BINARIES): bindir - $(WRITE) $(BINARIES) - -$(BASES): basedir - $(WRITE) $(BASES) - -$(TFSCRIPTS): tfscriptdir - $(WRITE) $(TFSCRIPTS) - -$(SHSCRIPTS): shscriptdir - $(WRITE) $(SHSCRIPTS) -# -# install -BIN: $(BINARIES) - $(INSTALL) $^ $(HOMEBINS) - -$(HOMEBASES): $(BASES) - $(COPYA) $^ $@ - -$(HOMETFSCRIPTS): $(TFSCRIPTS) - $(COPYA) $^ $@ - -$(HOMESHSCRIPTS): $(SHSCRIPTS) - $(COPYA) $^ $@ - -install: BIN $(HOMETFSCRIPTS) $(HOMEBASES) $(HOMESHSCRIPTS) - $(WRITE) "Installed" -# -# uninstall -uninstallbins: $(BINARIES) - $(foreach var,$(BINARIES),$(DELETE) $(HOME)/$(var);) - -uninstalldata: - $(RMFORCE) $(HOME)/$(TARGET) - -uninstall: uninstallbins uninstalldata - $(WRITE) "Uninstalled" \ No newline at end of file diff --git a/tools/provisioning/kvm_instance/README.md b/tools/provisioning/kvm_instance/README.md deleted file mode 100644 index 9fdda210..00000000 --- a/tools/provisioning/kvm_instance/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Assistance for creating an oci-kvm instance in OCI. - -## Prerequisites - -- terraform software installed -- oci-sdk installed and configured for direct authentication (for now) - -## Overview -This utility generates a terraform script which will create an instance in OCI which is ready to act as an oci-kvm server in OCI. The instance can be virtual (if supported by the hardware) as well as bare metal. -The instance will have all the necessary software packages installed as well as the required operating system configuration changes. -The **ocid** service will be enabled and running. It is advised to reboot the newly create instance after provisioning. -## Command line -```buildoutcfg -$ create_kvm_instance --help -usage: create_kvm_instance.py [-h] [-n DISPLAY_NAME] [-p PROFILE] - [-c CONFIGFILE] [-d DATADIR] [-f VARFILENAME] - -Configure oci utils auto test. - -Arguments: - -h, --help show this help message and exit - -n DISPLAY_NAME, --name DISPLAY_NAME - The display name of the instance to create. There is - no default, if not provided, the script asks for it. - -p PROFILE, --profile PROFILE - The profile in the cli/sdk config file, default is - DEFAULT. - -c CONFIGFILE, --config CONFIGFILE - The cli/sdk config file, default is ~/.oci/config. - -d DATADIR, --data-directory DATADIR - Root directory with data for auto test run, default is - ~//data. - -f VARFILENAME, --var-file VARFILENAME - filename to store the variables; the extension - .tfvars.json is added automatically. -``` -## Flow -- copy this tree/tar ball and expand to a working location -- chdir to **kvm_instance** directory -- `make` will show some help information -- install by executing `make install`, this will copy the template structure to a directory `~/create_kvm_instance` and the python code `create_kvm_instance.py` and the bash wrapper `create_kvm_instance` to `~/bin` -- run `~/bin/create_kvm_instance` which completes the variable data, creates a directory `~/oci_instance/` which contains the data for creating the instance, and creates create and destroy scripts. diff --git a/tools/provisioning/kvm_instance/base_instance/data.tf b/tools/provisioning/kvm_instance/base_instance/data.tf deleted file mode 100644 index a3980226..00000000 --- a/tools/provisioning/kvm_instance/base_instance/data.tf +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. diff --git a/tools/provisioning/kvm_instance/base_instance/main.tf b/tools/provisioning/kvm_instance/base_instance/main.tf deleted file mode 100644 index 3fd39bab..00000000 --- a/tools/provisioning/kvm_instance/base_instance/main.tf +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//YYYYvariable "instance_flex_memory_in_gbs" { -//YYYY description = "instance memorry size in GB." -//YYYY type = number -//YYYY} - -//YYYYvariable "instance_flex_ocpus" { -//YYYY description = "amount of instance ocpus." -//YYYY type = number -//YYYY} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "initial_script_path" { - description = "path to initial bash script" - type = string -} - -provider "oci" { - tenancy_ocid = var.tenancy_ocid - user_ocid = var.user_ocid - private_key_path = var.oci_private_key - fingerprint = var.fingerprint - region = var.region - // auth = var.auth -} - -resource "oci_core_instance" "test_instance" { - count = "1" - availability_domain = var.availability_domain - compartment_id = var.compartment_ocid - display_name = var.instance_display_name - shape = var.shape -//YYYY shape_config { -//YYYY memory_in_gbs = var.instance_flex_memory_in_gbs -//YYYY ocpus = var.instance_flex_ocpus -//YYYY } - - create_vnic_details { - subnet_id = var.subnet_ocid - display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - } - - source_details { - source_type = var.source_type - source_id = var.source_ocid - } - - preserve_boot_volume = false - - metadata = { - ssh_authorized_keys = file(var.ssh_public_key) - } - - timeouts { - create = "60m" - } - -} - -// install repo. -resource "null_resource" "update_to_latest" { - - provisioner "remote-exec" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.XXXX_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - script = var.initial_script_path - } -} - -resource "null_resource" "create_tail_log" { - connection { - type = "ssh" - agent = false - user = var.remote_user - host = oci_core_instance.test_instance.*.XXXX_ip[0] - timeout = "15m" - private_key = file(var.ssh_private_key) - } - - provisioner "file" { - content = "rm -f /var/tmp/oci-utils.log; touch /var/tmp/oci-utils.log; clear; tail -f /var/tmp/oci-utils.log" - destination = "/tmp/tail_log" - } -} - diff --git a/tools/provisioning/kvm_instance/base_instance/output.tf b/tools/provisioning/kvm_instance/base_instance/output.tf deleted file mode 100644 index 8cd3019a..00000000 --- a/tools/provisioning/kvm_instance/base_instance/output.tf +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - description = "Private IP of created instance." - value = oci_core_instance.test_instance.*.private_ip[0] -} - -//XXXXoutput "instance_public_ip" { -//XXXX description = "Public IPs of created instance." -//XXXX value = oci_core_instance.test_instance.*.public_ip[0] -//XXXX} - -output "boot_volume_ocid" { - description = "OCID of the boot volume of the created instance." - value = oci_core_instance.test_instance.*.boot_volume_id[0] -} - -output "instance_ocid" { - description = "OCID of the created instance." - value = oci_core_instance.test_instance.*.id[0] -} - diff --git a/tools/provisioning/kvm_instance/bin/create_kvm_instance b/tools/provisioning/kvm_instance/bin/create_kvm_instance deleted file mode 100644 index f1a349f1..00000000 --- a/tools/provisioning/kvm_instance/bin/create_kvm_instance +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. - -# utility assists with creating an oci-kvm instance. - -_PY3=/usr/bin/python3 -# s_dir=`${_PY3} -c 'import os.path ; import oci_utils.impl ; print (os.path.dirname(oci_utils.impl.__file__))' 2>/dev/null` - - -exec ${_PY3} ${HOME}/bin/create_kvm_instance.py $@ - diff --git a/tools/provisioning/kvm_instance/bin/create_kvm_instance.py b/tools/provisioning/kvm_instance/bin/create_kvm_instance.py deleted file mode 100755 index cc7278db..00000000 --- a/tools/provisioning/kvm_instance/bin/create_kvm_instance.py +++ /dev/null @@ -1,1695 +0,0 @@ -#!/bin/python3 -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http://oss.oracle.com/licenses/upl. - -""" -Creates scripts to create an instance using terraform. -""" -import argparse -import errno -import getpass -import inspect -import json -import logging -import os -import re -import shutil -import socket -import sys -import termios -import tty -from datetime import datetime -from subprocess import call - -import oci - -# -# locale -lc_all = 'en_US.UTF8' - -tfvars_file = 'instance_variables' -default_log = '/var/tmp/instance_config_' -default_instance_dir = 'oci_instances' -create_instance_source = 'create_kvm_instance' - - -default_values = { - "os_user": "whocares", - "os_user_home": "whocares", - "auth": "whocares", - "user_ocid": "whocares", - "server_ip": "whocares", - "fingerprint": "whocares", - "oci_private_key": "whocares", - "tenancy_ocid": "whocares", - "region": "whocares", - "ssh_public_key": "whocares", - "ssh_private_key": "whocares", - "compartment_ocid": "whocares", - "source_ocid": "whocares", - "subnet_ocid": "whocares", - # "vcn_ocid": "whocares", - # "network_compartment_ocid": "whocares", - "vnic_display_name": "whocares", - "availability_domain": "whocares", - "instance_display_name": "whocares", - "shape": "whocares", - # "authentication": "whocares", - "source_type": "whocares", - "remote_user": "whocares", - # "autotest_root": "whocares", - "log_file_path": "/logs", - "initial_script_path": "whocares", - # "dns_search_domains" : ".oracle.com", - # "dns_server_ip" : "100.110.7.250", - # "http_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", - # "https_proxy_url": "http://www-proxy-hqdc.us.oracle.com:80", - # "http_no_proxy": "169.254.169.254,.oraclecloud.com,.oraclecorp.com,.us.oracle.com" -} - -_logger = logging.getLogger(__name__) - - -def print_g(msg, term=True): - """ - Write msg to stdout and to file. - - Parameters - ---------- - msg: str - The text. - term: bool - If true, write to stdout. - - Returns - ------- - No return value. - """ - if term: - print('%s' % msg) - _logger.debug(msg) - - -def parse_args(): - """ - Parse the command line arguments. - -p | --profile - - Returns - ------- - The command line namespace. - """ - parser = argparse.ArgumentParser(description='Configure oci utils auto test.') - parser.add_argument('-n', '--name', - action='store', - dest='display_name', - help='The display name of the instance to create. There is no default, ' - 'if not provided, the script asks for it.') - parser.add_argument('-p', '--profile', - action='store', - dest='profile', - default='DEFAULT', - help='The profile in the cli/sdk config file, default is DEFAULT.') - parser.add_argument('-c', '--config', - action='store', - dest='configfile', - default='~/.oci/config', - help='The cli/sdk config file, default is ~/.oci/config.') - parser.add_argument('-d', '--data-directory', - action='store', - dest='datadir', - default='_DDDD_', - help='Root directory with data for auto test run, default is ~//data.') - parser.add_argument('-f', '--var-file', - action='store', - dest='varfilename', - default=tfvars_file, - help='filename to store the variables; the extension .tfvars.json is added automatically.') - parser._optionals.title = 'Arguments' - args = parser.parse_args() - return args - - -def _clear(): - """ - Clear screen. - - Returns - ------- - bool: True - """ - _ = call('clear' if os.name == 'posix' else 'cls') - return True - - -def _getch(): - """ - Read a single keypress from stdin. - - Returns - ------- - The resulting character. - """ - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(fd) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch - - -def _read_yn(prompt, yn=True, waitenter=False, suppose_yes=False, default_yn=False): - """ - Read yes or no form stdin, No being the default. - - Parameters - ---------- - prompt: str - The message. - yn: bool - Add (y/N) to the prompt if True. - waitenter: bool - Wait for the enter key pressed if True, proceed immediately - otherwise. - suppose_yes: bool - if True, consider the answer is yes. - default_yn: bool - The default answer. - Returns - ------- - bool: True on yes, False otherwise. - """ - yn_prompt = prompt + ' ' - # - # if yes is supposed, write prompt and return True. - if suppose_yes: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - return True - # - # add y/N to prompt if necessary. - if yn: - if default_yn: - yn_prompt += ' (Y/n)' - yn = 'Y' - else: - yn_prompt += ' (y/N) ' - yn = 'N' - # - # if wait is set, wait for return key. - if waitenter: - resp_len = 0 - while resp_len == 0: - resp = input(yn_prompt).lstrip() - resp_len = len(resp) - yn_i = list(resp)[0].rstrip() - # - # if wait is not set, proceed on any key pressed. - else: - _ = sys.stdout.write(yn_prompt) - sys.stdout.flush() - yn_i = _getch().rstrip() - - sys.stdout.write('\n') - if bool(yn_i): - yn = yn_i - return bool(yn.upper() == 'Y') - - -def _is_int(string_data): - """ - Verifies if string is a valid int. - - Parameters - ---------- - string_data: str - The string to be evaluated. - - Returns - ------- - bool: True on success, false otherwise. - """ - return re.match(r"[-+]?\d+$", string_data) is not None - - -def _get_current_user(): - """ - Get the current username. - - Returns - ------- - str: the username. - """ - return getpass.getuser() - - -def _get_current_user_home(): - """ - Get the home directory of the current user. - - Returns - ------- - str: the full path of the home directory. - """ - return os.path.expanduser('~') - - -def _from_stdin(prompt, default=None): - """ - Read from stdin, if default is not set to None, some input is expected. - - Parameters - ---------- - prompt: str - The stdin prompt. - default: - Default value. - - Returns - ------- - value read - """ - while True: - return_val = input('%-40s: ' % prompt) - if bool(return_val): - return return_val - if default is not None: - return default - - -def get_configdata(profile, configfile='~/.oci/config'): - """ - Read the oci sdk/cli config file. - - Parameters - ---------- - profile: str - the config profile. - configfile: str - the path of the configfile. - Returns - ------- - dict: the config data. - """ - sdkconfigfile = configfile - if configfile.startswith('~/'): - sdkconfigfile = os.path.expanduser('~') + configfile[1:] - config = oci.config.from_file(file_location=sdkconfigfile, profile_name=profile) - return config - - -class autotesttfvars: - """ - Manipulate the tfvar.json file. - """ - def __init__(self, tfvars_file): - """ - Initialise. - - Parameters - ---------- - tfvars_file: str - Full path of the tfvar.json file. - # sdkconfig: dict - # Contents of the sdk config file. - """ - self.json_file = tfvars_file - # self.sdkconfig = sdkconfig - try: - with open(self.json_file, 'rb') as tfvj: - self.jsondata = json.load(tfvj) - except Exception as e: - # - # Failed to read variable def file, falling back to idle defaults. - print_g('Failed to read %s, creating default' % self.json_file) - self.jsondata = default_values - - def __enter__(self): - return self - - def __exit__(self, xtype, value, traceback): - try: - with open(self.json_file, 'w') as tfvj: - json.dump(self.jsondata, tfvj, indent=4) - return True - except Exception as e: - raise Exception('Failed to write %s:' % self.json_file) from e - - def update_json_with_config(self, sdk_config): - """ - Update tf.json file with .oci/config data. - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g('\nCollecting data from sdk config file:') - self.jsondata['user_ocid'] = sdk_config['user'] - print_g('user ocid: %s' % sdk_config['user']) - self.jsondata['fingerprint'] = sdk_config['fingerprint'] - print_g('fingerprint %s' % sdk_config['fingerprint']) - self.jsondata['oci_private_key'] = sdk_config['key_file'] - print_g('oci_private_key: %s' % sdk_config['key_file']) - self.jsondata['tenancy_ocid'] = sdk_config['tenancy'] - print_g('tenancy_ocid: %s' % sdk_config['tenancy']) - self.jsondata['region'] = sdk_config['region'] - print_g('region: %s' % sdk_config['region']) - if _read_yn('Agree?', default_yn=True): - return True - return False - - def update_user(self, display_name): - """ - Update tf.json file with user related data. - - Parameters - ---------- - display_name: str - The instance display name - - Returns - ------- - bool: True on success, False otherwise. - """ - # - # os user data - current_user = _get_current_user() - if bool(self.jsondata['os_user']): - if _read_yn('\nReplace %s by %s' % (self.jsondata['os_user'], current_user), default_yn=True): - self.jsondata['os_user'] = current_user - else: - self.jsondata['os_user'] = _from_stdin('os user', default=current_user) - - current_user_home = _get_current_user_home() - if bool(self.jsondata['os_user_home']): - if _read_yn('Replace %s by %s' % (self.jsondata['os_user_home'], current_user_home), default_yn=True): - self.jsondata['os_user_home'] = current_user_home - else: - self.jsondata['os_user_home'] = _from_stdin('os user home', default=current_user_home) - # - # ssh keys - pub_key = current_user_home + '/.ssh/id_rsa.pub' - if bool(self.jsondata['ssh_public_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_public_key'], pub_key), default_yn=True): - self.jsondata["ssh_public_key"] = pub_key - else: - self.jsondata['ssh_publid_key'] = _from_stdin('ssh public key', default=pub_key) - priv_key = current_user_home + '/.ssh/id_rsa' - if bool(self.jsondata['ssh_private_key']): - if _read_yn('Replace %s by %s' % (self.jsondata['ssh_private_key'], priv_key), default_yn=True): - self.jsondata["ssh_private_key"] = priv_key - else: - self.jsondata['ssh_private_key'] = _from_stdin('ssh private key', default=priv_key) - # - # initial script - self.jsondata['initial_script_path'] = os.path.join(self.jsondata['os_user_home'], - default_instance_dir, - display_name, - 'sh_scripts/initial_config.sh') - # - # ip V4 address - thisipv4 = socket.gethostbyname(socket.gethostname()) - if bool(self.jsondata['server_ip']): - if _read_yn('Replace %s by %s' % (self.jsondata['server_ip'], thisipv4), default_yn=True): - self.jsondata['server_ip'] = thisipv4 - else: - self.jsondata['server_ip'] = _from_stdin('server ip address', default=thisipv4) - return True - - def update_image(self, image_data): - """ - Update tf.json file with image related data. - - Parameters - ---------- - image_data: dict - The image data - - Returns - ------- - bool: True on success, False otherwise. - """ - print_g(image_data) - for k, v in image_data.items(): - print_g('%30s %s' % (k, v)) - self.jsondata[k] = v - - return True - - def update_varia(self, variadata): - """ - Update various data. - - Parameters - ---------- - variadata: dict - The various data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in variadata.items(): - print_g('%30s %s' % (var_key, var_val)) - self.jsondata[var_key] = var_val - return True - - def update_gen_data(self, gendata): - """ - Update tf.json with generic data. - - Parameters - ---------- - gendata: dict - The generic data. - - Returns - ------- - bool: True on success, False otherwise. - """ - for var_key, var_val in gendata.items(): - self.jsondata[var_key] = var_val - return True - - -def _read_nb(prompt, min_val=1, max_val=64, default_val=1): - """ - Read an integer number from stdin. - - Parameters - ---------- - prompt: str - prompt - min_val: int - the smallest possible value. - max_val: int - the largest possible value. - default_val: int - default value if no input. - - Returns - ------- - int: the number. - """ - while 1 == 1: - read_nb = input("%s ==> " % prompt) - if not bool(read_nb): - read_nb = int(default_val) - if _is_int(read_nb): - rread_nb = int(read_nb) - if min_val <= rread_nb <= max_val: - break - print_g('Value %d out of range.' % rread_nb) - else: - print_g('Invalid input: %s' % read_nb) - _logger.debug('Value read from stdin: %d' % rread_nb) - return rread_nb - - -def _select_from(some_list, prompt, default_val=0): - """ - Select an item from a list. - - Parameters - ---------- - some_list: list - list of items. - prompt: str - prompt - default_val: int - default index value if no input. - - Returns - ------- - The list element. - """ - while 1 == 1: - selected_nb = input("%s ==> " % prompt) - if not bool(selected_nb): - selected_nb = str(default_val) - if _is_int(selected_nb): - select_index = int(selected_nb) - if 0 <= select_index < len(some_list): - break - print_g('Index %d out of range.' % select_index) - else: - print_g('Invalid input: %s' % selected_nb) - _logger.debug('Selected %s', some_list[select_index]) - return some_list[select_index] - - -def select_compartment(config_dict, prompt): - """ - Select a compartment in the tenancy. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - - prompt: str - The prompt - Returns - ------- - dict: the data of the compartment. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_compartments = oci_identity.list_compartments(config_dict['tenancy']) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for comp in oci_compartments.data: - print_g('%4d %-30s %s' % (oci_compartments.data.index(comp), comp.name, comp.id)) - return _select_from(oci_compartments.data, prompt) - - -def select_vcn(config_dict, compartment_id): - """ - Select a VCN. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the VCN - """ - try: - oci_vncclient = oci.core.VirtualNetworkClient(config_dict) - oci_vcns = oci_vncclient.list_vcns(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for vcn in oci_vcns.data: - print_g('%4d %-30s %s' % (oci_vcns.data.index(vcn), vcn.display_name, vcn.id)) - return _select_from(oci_vcns.data, 'Select VCN for instance.') - - -def select_subnet(config_dict, compartment_id, vcn_id): - """ - Select a subnet. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the subnet - """ - try: - oci_subnetclient = oci.core.VirtualNetworkClient(config_dict) - oci_subnets = oci_subnetclient.list_subnets(compartment_id, vcn_id=vcn_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for subnet in oci_subnets.data: - print_g('%4d %-30s %s' % (oci_subnets.data.index(subnet), subnet.display_name, subnet.id)) - return _select_from(oci_subnets.data, 'Select subnet instance.') - - -def select_image(config_dict, compartment_id): - """ - Select an image. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the image - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - # oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - # compartment_id).data - - oci_images_data = oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Zero').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Custom').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Oracle Linux').data - oci_images_data += oci.pagination.list_call_get_all_results(oci_imageclient.list_images, - compartment_id, - operating_system='Oracle Autonomous Linux').data - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for image in oci_images_data: - # print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.id)) - print_g('%4d %-40s %s' % (oci_images_data.index(image), image.display_name, image.operating_system)) - image_data = _select_from(oci_images_data, 'Select Image') - print_g(image_data, term=False) - return image_data - - -def select_availability_domain(config_dict, compartment_id): - """ - Select an availability domain. - - Parameters - ---------- - config_dict: dict - The oci configuration file data. - compartment_id: str - The compartment ocid - - Returns - ------- - dict: the availability domain. - """ - try: - oci_identity = oci.identity.IdentityClient(config_dict) - oci_availability_domains = oci_identity.list_availability_domains(compartment_id) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for domain in oci_availability_domains.data: - print_g('%4d %-30s %s' % (oci_availability_domains.data.index(domain), domain.name, domain.id)) - return _select_from(oci_availability_domains.data, 'Select availability domain.') - - -def select_shape(config_dict, image_ocid): - """ - Select a compatible shape for the image. - - Parameters - ---------- - imageid: str - The ocid pf the image. - - Returns - ------- - The shape. - """ - try: - oci_imageclient = oci.core.ComputeClient(config_dict) - oci_shapes = oci_imageclient.list_image_shape_compatibility_entries(image_ocid) - except oci.exceptions.ServiceError as e: - print_g('*** AUTHORISATION ERROR ***') - _logger.error('Authorisation error', exc_info=True) - sys.exit(1) - except Exception as e: - print_g('*** ERROR *** %s' % str(e)) - _logger.error('ERROR %s', str(e), exc_info=True) - sys.exit(1) - for shape_dict in oci_shapes.data: - print_g('%4d %-30s' % (oci_shapes.data.index(shape_dict), shape_dict.shape)) - return _select_from(oci_shapes.data, 'Select shape.') - - -def _get_display_name(): - """ - Read instance display name from stdin. - - Returns - ------- - str: the display name. - """ - return input('Instance Display Name: ') - - -def _get_authentication_method(): - """ - Determine the authentication method. - - Returns - ------- - str: the authentication method. - """ - _ = _clear() - print_g('Authentication method.\n', term=True) - auth_methods = ['ApiKey', 'InstancePrincipal'] - for authm in auth_methods: - print_g('%4d: %s' % (auth_methods.index(authm), authm)) - method = _select_from(auth_methods, 'Authentication method:') - print_g('Selected authentication method: %s\n' % method) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return method - - -def _get_remote_user(): - """ - Get the remote username. - - Returns - ------- - str: the username. - """ - _ = _clear() - print_g('Remote user.\n', term=True) - rem_user = input('\nRemote User Name: ') - print_g('Selected remote user name: %s\n' % rem_user) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return rem_user - - -def _get_http_proxy(default_proxy): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The http proxy url. - """ - new_url = input('http proxy url\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_https_proxy(default_proxy): - """ - Get the http proxy url. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The https proxy url. - """ - new_url = input('https proxy url\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_no_proxy(default_proxy): - """ - Get the no proxy list. - - Parameters - ---------- - default_proxy: str - The default value. - - Returns - ------- - The https proxy url. - """ - new_url = input('no proxy\n [%s] (ENTER to accept default):' % default_proxy) - if not bool(new_url): - new_url = default_proxy - return new_url - - -def _get_log_file(default_log_file): - """ - Get the log file path. - - Parameters - ---------- - default_log_file: str - The default path. - - Returns - ------- - The path tot the log file. - """ - _ = _clear() - print_g('Log file path.\n', term=True) - new_log_file = input('log file path\n [%s] (ENTER to accept default):' % default_log_file) - print_g('Selected log file path: %s\n' % new_log_file) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return new_log_file - - -def _get_dns_search_domain(): - """ - Get the dns search domain. - - Returns - ------- - str: The dns search domain, default is retrieved from /etc/resolv.conf. - """ - resolv_file = '/etc/resolv.conf' - search_domain = 'whocares' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'search' in rf_line: - search_domain = rf_line.split()[1] - break - return search_domain - - -def _get_dns_server_ip(): - """ - Get the dns server ipv4 - - Returns - ------- - str: The dns server ipv4 address., default is retrieved from /etc/resolv.conf. - """ - resolv_file = '/etc/resolv.conf' - nameserver = '8.8.8.8' - with open(resolv_file, 'r') as rf: - for rf_line in rf: - if 'nameserver' in rf_line: - nameserver = rf_line.split()[1] - break - return nameserver - - -def get_generic_data(): - """ - Get generic variables. - - Parameters - ---------- - gendata: str - path to generic data directory. - - Returns - ------- - dict: the generic variables. - """ - gen_data = { - # 'instance_display_name': _get_display_name(), - 'auth': _get_authentication_method(), - 'remote_user': _get_remote_user(), - # 'http_proxy_url': _get_http_proxy(default_values['http_proxy_url']), - # 'https_proxy_url': _get_https_proxy(default_values['https_proxy_url']), - # 'http_no_proxy': _get_no_proxy(default_values['http_no_proxy']), - 'log_file_path': _get_log_file(default_values['log_file_path']), - # 'dns_search_domains': _get_dns_search_domain(), - # 'dns_server_ip': _get_dns_server_ip() - } - return gen_data - - -def create_dir(dirname): - """ - Create a directory, make a backup copy if already exists. - - Parameters - ---------- - dirname: str - Full path - - Returns - ------- - bool: True on success, false otherwise. - """ - try: - if os.path.exists(dirname): - bck_name = dirname + '_%s' % datetime.now().strftime('%Y%m%d_%H%M') - os.rename(dirname, bck_name) - print_g('Renamed %s to %s' % (dirname, bck_name), term=False) - os.makedirs(dirname) - print_g('Created %s' % dirname) - except OSError as e: - if e.errno != errno.EEXIST: - print_g('Failed to create %s' % dirname, term=False) - return False - print_g('%s already exists, might cause problems.' % dirname, term=False) - return True - - -def copy_dir(src, dest): - """ - Copy a directory recursively. - - Parameters - ---------- - src:str - Source dir - dest: str - Destination dir - - Returns - ------- - bool: True on success, False otherwise - """ - try: - if os.path.exists(dest): - shutil.rmtree(dest) - shutil.copytree(src, dest, symlinks=False) - print_g('Copied %s to %s' % (src, dest)) - except Exception as e: - _logger.error('Failed to copy %s to %s: %s', src, dest, str(e)) - return False - return True - - -def write_bash(fn, cmd): - """ - Write a command to the script file fn. - - Parameters - ---------- - fn: str - Full path of the script file. - cmd: str - The string. - - Returns - ------- - bool: True or False - """ - try: - if not os.path.exists(fn): - with open(fn, 'w') as fd: - fd.write('#!/bin/bash\n') - fd.flush() - os.chmod(fn, 0o755) - with open(fn, 'a') as fd: - fd.write('%s\n' % cmd) - fd.flush() - fd.write('RETVAL=${?}\n') - fd.flush() - fd.write('if [ $RETVAL -ne 0 ]; then\n') - fd.flush() - fd.write(' echo "%s failed"\n' % cmd) - fd.flush() - fd.write(' exit $RETVAL\n') - fd.flush() - fd.write(' echo "%s succeeded"\n' % cmd) - fd.write('fi\n') - fd.flush() - return True - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - return False - - -def init_struct(instance_name): - """ - Initialise config struct. - - Parameters - ---------- - instance_name: str - The instance display name. - - Returns - ------- - dict: the config structure. - """ - # - # exec dir - data = dict() - exec_dir = inspect.getfile(inspect.currentframe()) - data['instance_display_name'] = instance_name - data['exec_dir'] = os.path.dirname(exec_dir) - data['base_exec_dir'] = os.path.dirname(exec_dir) - return data - - -def get_user_data(data): - """ - Collect operator data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - data['operator'] = _get_current_user() - data['operator_home'] = _get_current_user_home() - print_g('Username: %s' % data['operator']) - print_g('Home: %s' % data['operator_home']) - return data - - -def create_directories(data, args): - """ - Create directories for scripts. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - def_base_dir = data['operator_home'] + '/' + default_instance_dir - instance_display_name = data['instance_display_name'] - data['def_instance_dir'] = def_base_dir + '/' + instance_display_name - data['def_data_dir'] = def_base_dir + '/' + instance_display_name + '/data' - data['base_instance_dir'] = def_base_dir + '/' + instance_display_name + '/base_instance' - data['def_tf_scripts_dir'] = def_base_dir + '/' + instance_display_name + '/tf_scripts' - data['def_sh_scripts_dir'] = def_base_dir + '/' + instance_display_name + '/sh_scripts' - if args.datadir != '_DDDD_': - data['def_data_dir'] = args.datadir + '/data' - data['def_tf_scripts_dir'] = args.datadir + '/tf_scripts' - data['def_sh_scripts_dir'] = args.datadir + '/sh_scripts' - data['base_instance_dir'] = args.datadir + '/base_instance' - print_g('Default instance dir %s' % data['def_instance_dir']) - print_g('Default data dir %s' % data['def_data_dir']) - print_g('Base instance dir %s' % data['base_instance_dir']) - print_g('Default tf_scripts dir %s' % data['def_tf_scripts_dir']) - print_g('Default sh_scripts dir %s' % data['def_sh_scripts_dir']) - if not create_dir(data['def_instance_dir']): - sys.exit(1) - if not create_dir(data['def_tf_scripts_dir']): - sys.exit(1) - if not create_dir(data['def_sh_scripts_dir']): - sys.exit(1) - if not create_dir(data['def_data_dir']): - sys.exit(1) - if not create_dir(data['base_instance_dir']): - sys.exit(1) - return data - - -def copy_scripts(data): - """ - Copy the tf scripts in place. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - # if not copy_dir(operator_home + '/create_instance/base_instance', base_instance_dir): - if not copy_dir(os.path.join(operator_home, create_instance_source, 'base_instance'), base_instance_dir): - print_g('Failed to copy %s' % base_instance_dir) - sys.exit(1) - def_tf_scripts_dir = data['def_tf_scripts_dir'] - # if not copy_dir(operator_home + '/create_instance/tf_scripts', def_tf_scripts_dir): - if not copy_dir(os.path.join(operator_home, create_instance_source, 'tf_scripts'), def_tf_scripts_dir): - print_g('Failed to copy %s' % def_tf_scripts_dir) - sys.exit(1) - def_sh_scripts_dir = data['def_sh_scripts_dir'] - # if not copy_dir(operator_home + '/create_instance/sh_scripts', def_sh_scripts_dir): - if not copy_dir(os.path.join(operator_home, create_instance_source, 'sh_scripts'), def_sh_scripts_dir): - print_g('Failed to copy %s' % def_sh_scripts_dir) - sys.exit(1) - return True - - -def update_public_ip(data, public_ip): - """ - Update the script for public or private ip. - - Parameters - ---------- - data: dict - The configuration data. - public_ip: bool - If True set for public ip. - - Returns - ------- - bool: True - """ - operator_home = data['operator_home'] - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['def_tf_scripts_dir'] - api_key = tf_scripts_dir + '/api_key.tf' - output_b = base_instance_dir + '/output.tf' - output_t = tf_scripts_dir + '/output.tf' - main_b = base_instance_dir + '/main.tf' - iptype = 'public' if public_ip else 'private' - print_g('operator home %s' % operator_home, term=False) - print_g('base instance dir %s' % base_instance_dir, term=False) - print_g('api key %s' % api_key, term=False) - print_g('output b %s' % output_b, term=False) - print_g('main b %s' % main_b, term=False) - print_g('iptype %s' % iptype, term=False) - - # - # tf_scripts/api_key - with open(api_key, 'r+') as fx: - api_text = fx.read() - api_text = re.sub('XXXX', iptype, api_text) - fx.seek(0) - fx.write(api_text) - print_g('api text: %s' % api_text, term=False) - fx.truncate() - # - # base_instance/main - with open(main_b, 'r+') as fx: - main_text = fx.read() - main_text = re.sub('XXXX', iptype, main_text) - fx.seek(0) - fx.write(main_text) - print_g('main text: %s' % main_text, term=False) - fx.truncate() - # - # output public ip if one available - if public_ip: - # - # base_instance/output - with open(output_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//XXXX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # tf_scripts/output - with open(output_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//XXXX', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def update_flex(data): - """ - Update the terraform scripts for usage with Flex shapes. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - bool: True - """ - # - # tf_scripts/main.tf - base_instance_dir = data['base_instance_dir'] - tf_scripts_dir = data['def_tf_scripts_dir'] - main_t = tf_scripts_dir + '/main.tf' - main_b = base_instance_dir + '/main.tf' - with open(main_t, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//YYYY', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - # - # base_instance/main.tf - with open(main_b, 'r+') as fx: - output_text = fx.read() - output_text = re.sub('//YYYY', '', output_text) - fx.seek(0) - fx.write(output_text) - print_g('output text: %s' % output_text, term=False) - fx.truncate() - return True - - -def get_oci_config(data, args): - """ - Get the oci configuration. - - Parameters - ---------- - data: dict - The configuration data. - args: namespace - The command line namespace. - - Returns - ------- - dict: the configuration data. - """ - cfg_dict = get_configdata(args.profile, args.configfile) - print_g('Configuration') - for k, v in cfg_dict.items(): - print_g('%40s: %s' % (k, v)) - data['oci_config'] = cfg_dict - return data - - -def get_instance_compartment(data): - """ - Get the compartment data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Compartment.\n', term=True) - instance_compartment = select_compartment(data['oci_config'], "Select compartment for the instance.") - print_g(instance_compartment, term=False) - print_g('Selected compartment: %s\n' % instance_compartment.name) - data['compartment'] = instance_compartment - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_availability_domain(data): - """ - Get the availablility domain data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Availability domain.\n', term=True) - availability_domain = select_availability_domain(data['oci_config'], data['compartment'].id) - print_g(availability_domain, term=False) - print_g('Selected availability domain: %s\n' % availability_domain.name) - data['availability_domain'] = availability_domain.name - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_network_compartment(data): - """ - Get the network compartment. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Network compartment.\n', term=True) - network_compartment = select_compartment(data['oci_config'], "Select compartment for the network.") - print_g(network_compartment, term=False) - print_g('Selected network compartment: %s\n' % network_compartment.name) - data['network_compartment'] = network_compartment - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_vcn(data): - """ - Get the VCN data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Virtual cloud network.\n', term=True) - vcn = select_vcn(data['oci_config'], data['network_compartment'].id) - data['vcn'] = vcn - print_g(vcn, term=False) - print_g('Selected VCN: %s\n' % vcn.display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_subnet(data): - """ - Get the subnet data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Subnet.\n', term=True) - subnet = select_subnet(data['oci_config'], data['network_compartment'].id, vcn_id=data['vcn'].id) - data['subnet'] = subnet - print_g(subnet, term=False) - print_g('Selected subnet: %s\n' % subnet.display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_public_ip(): - """ - Request for public ip. - - Returns - ------- - bool: true or false. - """ - _ = _clear() - return True if _read_yn('Assign a public IPv4 address?') else False - - -def get_image(data): - """ - Get the image data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Image.\n', term=True) - data['image'] = select_image(data['oci_config'], data['compartment'].id) - print_g(data['image'].id, term=False) - print_g('Selected image: %s\n' % data['image'].display_name) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_shape(data): - """ - Get the instance shape. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Shape.\n', term=True) - data['shape'] = select_shape(data['oci_config'], data['image'].id) - print_g(data['shape'], term=False) - print_g('Selected shape: %s\n' % data['shape'].shape) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - return data - - -def get_flex_data(data): - """ - Get the Flex shape data. - - Parameters - ---------- - data: dict - The configuration data. - - Returns - ------- - dict: the configuration data. - """ - _ = _clear() - print_g('Flex shape data.\n', term=True) - # - # memory - data['instance_flex_memory_in_gbs'] = _read_nb('Memory in GB', default_val=4, max_val=256) - print_g(data['instance_flex_memory_in_gbs'], term=False) - print_g('Selected memory size: %dGB' % data['instance_flex_memory_in_gbs']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - # cpus - data['instance_flex_ocpus'] = _read_nb('Number of OCPUs', default_val=2, max_val=18) - print_g(data['instance_flex_ocpus'], term=False) - print_g('Selected number of OCPUs: %d' % data['instance_flex_ocpus']) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - # - return data - - -def print_config_data(xx): - """ - Print dict. - - Parameters - ---------- - xx: dict - The data to print. - - Returns - ------- - No return value. - """ - for k,v in xx.items(): - print('%30s: %s' % (k,v)) - - -def write_scripts(data): - """ - Write the scripts. - Parameters - ---------- - data: the configuration data. - - Returns - ------- - No return value. - """ - def_log_dir = data['def_instance_dir'] - print_g('Run\n' - 'terraform -chdir=%s init\n' - 'terraform -chdir=%s validate\n' - 'terraform -chdir=%s plan -var-file=%s\n' - 'terraform -chdir=%s apply -var-file=%s -auto-approve | tee %s/creation.log\n' - 'terraform -chdir=%s destroy -var-file=%s -auto-approve' - % (data['def_tf_scripts_dir'], - data['def_tf_scripts_dir'], - data['def_tf_scripts_dir'], data['tfvarsfile'], - data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir, - data['def_tf_scripts_dir'], data['tfvarsfile'])) - create_script = data['def_instance_dir'] + '/create' - if not write_bash(create_script, 'terraform -chdir=%s init' - % data['def_tf_scripts_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s validate' - % data['def_tf_scripts_dir']): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s plan --var-file=%s' - % (data['def_tf_scripts_dir'], data['tfvarsfile'])): - sys.exit(1) - if not write_bash(create_script, 'terraform -chdir=%s apply --var-file=%s -auto-approve | tee %s/creation.log' - % (data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir)): - sys.exit(1) - destroy_script = data['def_instance_dir'] + '/destroy' - if not write_bash(destroy_script, 'terraform -chdir=%s destroy --var-file=%s -auto-approve | tee %s/destruction.log' - % (data['def_tf_scripts_dir'], data['tfvarsfile'], def_log_dir)): - sys.exit(1) - print_g('\nor\n%s\n%s' % (create_script, destroy_script)) - - -def main(): - """ - Configure auto tests. - - Returns - ------- - int: 0 on success, raises exception on failure. - """ - # - # locale - os.environ['LC_ALL'] = "%s" % lc_all - # - # parse the commandline - args = parse_args() - # - # clear - _ = _clear() - # - # instance name to create - instance_display_name = args.display_name if args.display_name is not None else _get_display_name() - # - # exec dir - config_data = init_struct(instance_display_name) - # - # initialise logging - logging.basicConfig(filename=default_log + instance_display_name + '.log', - level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s (%(module)s:%(lineno)s) - %(message)s') - # - # show initial data - print_g('Display name: %s' % instance_display_name) - print_g('exec dir: %s' % config_data['exec_dir'], term=False) - print_g('base exec dir: %s' % config_data['base_exec_dir'], term=False) - # - # current user - config_data = get_user_data(config_data) - # - # initialise data structure - image_data = dict() - # - # create directories - config_data = create_directories(config_data, args) - # - # copy the scripts in place. - _ = copy_scripts(config_data) - # - # tf variable file path - config_data['tfvarsfile'] = config_data['def_data_dir'] + '/' + args.varfilename + '.tfvars.json' - print_g('tfvars file: %s' % config_data['tfvarsfile']) - # - # Get configuration data from config file. - config_data = get_oci_config(config_data, args) - if not _read_yn('Continue?', default_yn=True): - sys.exit(1) - _ = _clear() - # - # compose var file. - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_json_with_config(config_data['oci_config']) - print_g('Updated variables with config data', term=True) - _ = atfv.update_user(instance_display_name) - print_g('Updated variables with operator data', term=True) - except Exception as e: - print_g('***ERROR*** %s' % str(e), term=True) - # - # Instance compartment - config_data = get_instance_compartment(config_data) - image_data['compartment_ocid'] = config_data['compartment'].id - # _ = _clear() - # - # Availability domain - config_data = get_availability_domain(config_data) - image_data['availability_domain'] = config_data['availability_domain'] - # - # Network compartment - config_data = get_network_compartment(config_data) - # - # Virtual Cloud Network - config_data = get_vcn(config_data) - # - # Subnets - config_data = get_subnet(config_data) - image_data['subnet_ocid'] = config_data['subnet'].id - # - # Public ip - # Public ip - image_data['assign_public_ip'] = get_public_ip() - # - # update public ip - _ = update_public_ip(config_data, image_data['assign_public_ip']) - # - # Type - image_data['source_type'] = 'image' - # - # Images - config_data = get_image(config_data) - image_data['source_ocid'] = config_data['image'].id - # - # Shape - config_data = get_shape(config_data) - image_data['shape'] = config_data['shape'].shape - # - # is shape Flex? - if bool(re.search('Flex', image_data['shape'])): - config_data = get_flex_data(config_data) - image_data['instance_flex_memory_in_gbs'] = config_data['instance_flex_memory_in_gbs'] - image_data['instance_flex_ocpus'] = config_data['instance_flex_ocpus'] - _ = update_flex(config_data) - # - # get generic variables - gen_data = get_generic_data() - gen_data['instance_display_name'] = instance_display_name - # - # various data - varia_data = {'vnic_display_name': instance_display_name} - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_varia(varia_data) - print_g('Updated various data.') - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - # - # update tfvars file - try: - with autotesttfvars(config_data['tfvarsfile']) as atfv: - _ = atfv.update_image(image_data) - print_g('Updated variables with image data.') - _ = atfv.update_gen_data(gen_data) - print_g('Updated variables with generic data.') - except Exception as e: - print_g('***ERROR*** %s' % str(e)) - # - print_g('Wrote configuration to %s' % config_data['tfvarsfile']) - # - write_scripts(config_data) - sys.exit(0) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/provisioning/kvm_instance/gen_scripts/initial_config.sh b/tools/provisioning/kvm_instance/gen_scripts/initial_config.sh deleted file mode 100644 index 4eeecce6..00000000 --- a/tools/provisioning/kvm_instance/gen_scripts/initial_config.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash -x -# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -# Licensed under the Universal Permissive License v 1.0 as shown -# at http:/oss.oracle.com/licenses/upl. - -RPM=$(command -v rpm) -GREP=$(command -v grep) -FIND=$(command -v find) -SED=$(command -v sed) -COPY=cp -WRITE=echo -NOW=$(date +"%Y%m%d_%H%M") -MKDIR=$(command -v mkdir) -DNF=dnf -YUM=yum -SYSTEMCTL=$(command -v systemctl) -SUDO=$(command -v sudo) -INITIALLOG=/logs/initial.log -OSVERSION=$(${SED} -rn 's/.*([0-9])\.[0-9].*/\1/p' /etc/redhat-release) -# -# -# if dnf exists, this is OL8 or later, use dnf. -if ! command -v dnf; then - # - # OL7 - INSTALLRPM=$(command -v yum) - ${SUDO} ${INSTALLRPM} install --assumeyes python36-libvirt - ${SUDO} ${INSTALLRPM} install --assumeyes git - ${SUDO} --login ${installrpm}-config-manager --enablerepo ol${OSVERSION}_kvm_utils - ${SUDO} ${INSTALLRPM} --assumeyes install oci-utils-kvm \ - qemu-kvm \ - qemu-img \ - libvirt \ - libvirt-python \ - libvirt-client \ - virt-install \ - virt-viewer -else - # - # OL8+ - INSTALLRPM=$(command -v dnf) - ${SUDO} ${INSTALLRPM} install --assumeyes python3-libvirt - ${SUDO} ${INSTALLRPM} install --assumeyes git - ${SUDO} ${INSTALLRPM} --assumeyes install oci-utils-kvm \ - qemu-kvm \ - qemu-img \ - libvirt \ - python3-libvirt \ - libvirt-client \ - virt-install \ - virt-viewer \ - @virt -fi -# -# Disable lvm devices -${SUDO} ${COPY} /etc/lvm/lvm.conf /etc/lvm/lvm.conf.${NOW} -${SUDO} ${SED} -i '/# global_filter =/a\\tglobal_filter = [ "r|/dev/sd*|" ]' /etc/lvm/lvm.conf -# -# Preparing the KVM Server for virtualization -# Backup Grub File -${SUDO} ${COPY} /etc/default/grub /etc/default/grub.${NOW} -# -# Edit grub and include the following options -GRUB_FILE=/etc/default/grub -GRUB_STRING="intel_iommu=on amd_iommu=on" -${SUDO} ${SED} -i "/^GRUB_CMDLINE_LINUX=/s/\"$/ ${GRUB_STRING}\"/" ${GRUB_FILE} -# -# Enable nested virt (Intel only AMD is not suported yet) -${WRITE} 'options kvm-intel nested=Y'|${SUDO} tee /etc/modprobe.d/kvm_intel.conf >/dev/null -# Experimental AMD nested virtualization -${WRITE} 'options kvm-amd nested=1'|${SUDO} tee /etc/modprobe.d/kvm_amd.conf >/dev/null -# -# Enable tuned -${SUDO} systemctl enable tuned -${SUDO} systemctl start tuned -${SUDO} tuned-adm profile virtual-host -# -# Recreate grub to validate all the changes -${SUDO} ${COPY} /boot/efi/EFI/redhat/grub.cfg /boot/efi/EFI/redhat/grub.cfg.${NOW} -${SUDO} grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg -# -# Allow the opc user to use virsh without the need for sudo -${SUDO} ${COPY} /etc/libvirt/libvirtd.conf /etc/libvirt/libvirtd.conf.${NOW} -${SUDO} ${SED} -i\ - -e 's/^#unix_sock_group .*/unix_sock_group = "libvirt"/'\ - -e 's/^#unix_sock_ro_perms .*/unix_sock_ro_perms = "0770"/'\ - -e 's/^#unix_sock_rw_perms .*/unix_sock_rw_perms = "0770"/'\ - /etc/libvirt/libvirtd.conf -${SUDO} ${SED} -i\ - -e 's,^#uri_default \(.*\),uri_default \1,'\ - /etc/libvirt/libvirt.conf -# -# Enable ocid service -${SUDO} systemctl enable ocid.service -# start the ocid service -${SUDO} systemctl start ocid.service -# Add the libvirt group to the opc user to allow easier virsh usage -${SUDO} usermod -aG libvirt opc -${WRITE} 'export LIBVIRT_DEFAULT_URI="qemu:///system"' >> /home/opc/.bashrc -# -# -${SUDO} rm -f /tmp/custom*sh -history -c -# - - diff --git a/tools/provisioning/kvm_instance/tf_scripts/api_key.tf b/tools/provisioning/kvm_instance/tf_scripts/api_key.tf deleted file mode 100644 index ac62c782..00000000 --- a/tools/provisioning/kvm_instance/tf_scripts/api_key.tf +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -resource "null_resource" "oci_sdk_config" { - depends_on = [module.base_instance] - provisioner "file" { - source = var.oci_private_key - destination = "/tmp/oci_private_key.pem" - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - } - provisioner "remote-exec" { - connection { - type = "ssh" - user = var.remote_user - agent = false - host = module.base_instance.instance_XXXX_ip - timeout = "15m" - private_key = file(var.ssh_private_key) - } - inline = [ - "/bin/sudo --preserve-env mkdir -p /root/.oci", - "/bin/sudo --preserve-env cp /tmp/oci_private_key.pem /root/.oci/$(basename ${var.oci_private_key})", - "/bin/sudo --preserve-env echo [DEFAULT] > /tmp/config", - "/bin/sudo --preserve-env echo user=${var.user_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo fingerprint=${var.fingerprint} >> /tmp/config", - "/bin/sudo --preserve-env echo key_file=/root/.oci/$(basename ${var.oci_private_key}) >> /tmp/config", - "/bin/sudo --preserve-env echo tenancy=${var.tenancy_ocid} >> /tmp/config", - "/bin/sudo --preserve-env echo region=${var.region} >> /tmp/config", - "/bin/sudo cp /tmp/config /root/.oci/config", - "/bin/sudo chmod -R 600 /root/.oci/" - ] - } -} diff --git a/tools/provisioning/kvm_instance/tf_scripts/data.tf b/tools/provisioning/kvm_instance/tf_scripts/data.tf deleted file mode 100644 index 8130d272..00000000 --- a/tools/provisioning/kvm_instance/tf_scripts/data.tf +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -data "oci_identity_availability_domains" "ads" { - compartment_id = var.tenancy_ocid -} - diff --git a/tools/provisioning/kvm_instance/tf_scripts/main.tf b/tools/provisioning/kvm_instance/tf_scripts/main.tf deleted file mode 100644 index fc8472e7..00000000 --- a/tools/provisioning/kvm_instance/tf_scripts/main.tf +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -variable "os_user" { - description = "os user." - type = string -} - -variable "os_user_home" { - description = "operator home directory" - type = string -} - -variable "server_ip" { - description = "this server ipv4 address" - type = string -} - -variable "tenancy_ocid" { - description = "tencancy identification." - type = string -} - -variable "compartment_ocid" { - description = "compartment identification." - type = string -} - -variable "availability_domain" { - description = "availability domain name." - type = string -} - -variable "user_ocid" { - description = "user identification." - type = string -} - -variable "oci_private_key" { - description = "path to use private key for OCI." - type = string -} - -variable "fingerprint" { - description = "OCI key fingerprint." - type = string -} - -variable "region" { - description = "oci region name." - type = string -} - -variable "shape" { - description = "shape selection." - type = string -} - -//YYYYvariable "instance_flex_memory_in_gbs" { -//YYYY description = "instance memorry size in GB." -//YYYY type = number -//YYYY} - -//YYYYvariable "instance_flex_ocpus" { -//YYYY description = "amount of instance ocpus." -//YYYY type = number -//YYYY} - -variable "source_ocid" { - description = "source identification." - type = string -} - -variable "source_type" { - description = "source type identification." - type = string -} - -variable "instance_display_name" { - description = "instance display name." - type = string -} - -variable "assign_public_ip" { - description = "assign a public ip." - type = bool -} - -variable "vnic_display_name" { - description = "vnic display name." - type = string -} - -variable "subnet_ocid" { - description = "subnet identification." - type = string -} - -variable "ssh_public_key" { - description = "user authorized keys path." - type = string -} - -variable "remote_user" { - description = "user to connect to remote with sudo privileges." - type = string -} - -variable "ssh_private_key" { - description = "local user private key path." - type = string -} - -variable "auth" { - description = "authentication method." - type = string -} - -variable "log_file_path" { - description = "path to logfile" - type = string -} - -variable "initial_script_path" { - description = "path to initial bash script" - type = string -} - -module "base_instance"{ - source = "../base_instance" - os_user = var.os_user - os_user_home = var.os_user_home - server_ip = var.server_ip - auth = var.auth - tenancy_ocid = var.tenancy_ocid - compartment_ocid = var.compartment_ocid - availability_domain = var.availability_domain - user_ocid = var.user_ocid - fingerprint = var.fingerprint - region = var.region - shape = var.shape -//YYYY instance_flex_memory_in_gbs = var.instance_flex_memory_in_gbs -//YYYY instance_flex_ocpus = var.instance_flex_ocpus - source_ocid = var.source_ocid - source_type = var.source_type - instance_display_name = var.instance_display_name - vnic_display_name = var.vnic_display_name - assign_public_ip = var.assign_public_ip - subnet_ocid = var.subnet_ocid - ssh_public_key = var.ssh_public_key - oci_private_key = var.oci_private_key - remote_user = var.remote_user - ssh_private_key = var.ssh_private_key - log_file_path = var.log_file_path - initial_script_path = var.initial_script_path -} diff --git a/tools/provisioning/kvm_instance/tf_scripts/output.tf b/tools/provisioning/kvm_instance/tf_scripts/output.tf deleted file mode 100644 index 2f326d2b..00000000 --- a/tools/provisioning/kvm_instance/tf_scripts/output.tf +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -output "instance_private_ip" { - value = module.base_instance.instance_private_ip -} - -//XXXXoutput "instance_public_ip" { -//XXXX value = module.base_instance.instance_public_ip -//XXXX} - -output "boot_volume_ocid" { - value = module.base_instance.boot_volume_ocid -} - -output "instance_ocid" { - value = module.base_instance.instance_ocid -} \ No newline at end of file diff --git a/tools/provisioning/kvm_instance/tf_scripts/version.tf b/tools/provisioning/kvm_instance/tf_scripts/version.tf deleted file mode 100644 index 3d2fdf15..00000000 --- a/tools/provisioning/kvm_instance/tf_scripts/version.tf +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. -// Licensed under the Universal Permissive License v 1.0 as shown -// at http:/oss.oracle.com/licenses/upl. - -terraform { - required_providers { - oci = ">= 3.56.0" - } -} \ No newline at end of file diff --git a/usr/share/man/man8/oci-image-expand.8 b/usr/share/man/man8/oci-image-expand.8 new file mode 100644 index 00000000..74a4463d --- /dev/null +++ b/usr/share/man/man8/oci-image-expand.8 @@ -0,0 +1,103 @@ +.\" Process this file with +.\" groff -man -Tascii oci-image-expand.8 +.\" +.\" Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. +.\" + +.TH OCI-IMAGE-EXPAND 8 "23 May 2024" Linux "User Manuals" +.SH NAME +oci-image-expand \- Allows a user to restore key functionality not included in an Oracle Linux 9 Minimal Image. + +.SH SYNOPSIS +.B /usr/libexec/oci-image-cleanup [-h|--help] + +.SH DESCRIPTION +The oci-image-expand utility gives the user of an Oracle Linux 9 Minimal Image instance options to restore key functionality. There are two sets of options: default options and reboot required options. + +.P The default options are always restored -- they are not user selectable. Restoring the default options will not increase the instance boot time. + +.P There are three user selectable options, each of which will require a reboot to be fully activated: enabling SELinux, enabling Kdump and enabling Ksplice. Restoring a reboot required option will increase instance boot time. + +.P Output from the oci-image-expand utility will be logged at /var/log/oci-image-expand.log. + +.SS WARNINGS + +.SB THIS UTILITY SHOULD NOT BE RUN ON NON-MINIMAL IMAGES +.P After the oci-image-expand utility is run and all features have been applied via a reboot, instance boot performance is no longer guaranteed to be as before. + +.P Some of the changes applied by the oci-image-expand utility will impact user configured areas. For example, the oci-image-expand utility restores cloud-init config to default platform image settings, hence any user configured cloud-config changes will be over-written. Also note that that enabling Ksplice will result in a re-install of the oci-linux-config package to ensure that the new access key is stored in the proper configuration file. + +.BR oci-image-expand(8) +requires sudo privileges. + +.SH OPTIONS +The oci-image-expand utility clears the screen and presents the user the following menu. + +oci-image-expand + Adds key functionality not included in an OL9 minimal image. + Default added functions include systemd services, diagnostic packages, cloud configuration settings as well as configuring and enabling swap on the instance. + User selectable functions (requiring reboot) -- SELinux, Kdump, Ksplice. + +Please select the set of reboot required functions, if any + Selecting a function transitions from not selected [ ] to selected [+] or vice versa + +[ ] 0) All reboot options + +[ ] 1) Enable SELinux + +[ ] 2) Enable Kdump + +[ ] 3) Enable Ksplice + +Select the desired options using their number (again to uncheck, ENTER when done): + +.SH RETURN VALUES + +The oci-image-expand utility passes back a return value upon exit. For successful completion 0 is returned, else a non-zero error value is returned. The complete list of error values is shown in the ERRORS section. If an attempted command fails, then the oci-image-expand utility will rollback the failing command to the last good state. + +.SH ERRORS + +The possible return values are: + +0 Successful completion + +1 Enabling auditd failed + +2 Enabling ldconfig failed + +3 Enabling DNF makecache timer failed + +4 Enabling Oracle Cloud Agent Updater failed + +5 Enabling Performance Co-Pilot failed + +6 Enabling diagnostic RPMs failed + +7 Enabling cloud init modules failed + +8 Enabling cloud config modules failed + +9 Enabling cloud final modules failed + +10 Enabling SELinux failed + +11 Enabling Kdump failed + +12 Enabling Ksplice failed + +20 Failed to obtain valid operating system level + +21 Operating system version is not Oracle Linux 9 + +22 Processor type is not x64_64 + +23 Operating system is not Oracle Linux 9 Minimal Image + +24 User does not have sudo privileges + +.SH SEE ALSO + +More info on Oracle Linux 9 Minimal images can be found here: + +https://docs.oracle.com/iaas/oracle-linux/minimal/index.htm +