diff --git a/scripts/instruqt/create_language_clone.sh b/scripts/instruqt/create_language_clone.sh new file mode 100644 index 0000000..d25c4a3 --- /dev/null +++ b/scripts/instruqt/create_language_clone.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# Script to ease the creation of different languages versions of existing Instruqt labs. +# Author/s: Raul Mahiques +# License: GPLv3 +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with this program. If not, see . + + +# Make it look nicer if possible +if [ -t 1 ] && command -v tput >/dev/null && [ "$(tput colors)" -ge 8 ]; then + export ERROR='\033[0;31m' + export SUCCESS='\033[0;32m' + export WARNING='\033[1;33m' + export PROGRESS='\033[1m' + export NC='\033[0m' +else + export ERROR='' SUCESS='' WARNING='' NC='' PROGRESS='' +fi + +# Verification and parameters handling + +git rev-parse --is-inside-work-tree &>/dev/null || { echo -e "${ERROR}ERROR${NC}: This command must run on inside the git repository folder" ; exit 1 ; } +[[ "$1" == "" ]] && { echo -e "${ERROR}ERROR${NC}: arguments not provided\n${PROGRESS}Example${NC}:\n\t$0 []" ; exit 1 ; } +[[ "$2" == "" ]] && { echo -e "${ERROR}ERROR${NC}: Language not provided\n${PROGRESS}Example${NC}:\n\t$0 []" ; exit 1 ; } + +lab=${1//\.\/} +lab=${lab//\/} +lang=${2,,} +mode=${3:-a} + + +[[ -d "$lab" ]] || { echo -e "${ERROR}ERROR${NC}: lab folder \"${lab}\" not found or not a directory\n${PROGRESS}Example${NC}:\n\t$0 []" ; exit 1 ; } +[[ ${#lang} -gt 2 ]] && { echo -e "${ERROR}ERROR${NC}: Language be only 2 characters, \"${lang}\" has ${#lang}\n${PROGRESS}Example${NC}:\n\t$0 ${lab} es b" ; exit 1 ; } +[[ -d "${lab}-${lang}" ]] && { echo -e "${ERROR}ERROR${NC}: There is already a lab with the same language \"${lab}-${lang}\""; exit 1 ; } + + + +if [[ "" == "a" ]] +then + # Start the process + mkdir ${lab}-${lang} + + + cp -r ${lab}/[0-9]* ${lab}-${lang}/ + + cd ${lab} + find -type d |while read line + do + mkdir -p "../${lab}-${lang}/$line" + done + + find assets -type f |while read line + do + ln "../${lab}/$line" "../${lab}-${lang}/$line" + done + find track_scripts -type f |while read line + do + ln "../${lab}/$line" "../${lab}-${lang}/$line" + done + + echo -e "${PROGRESS}Change all the text inside the following files:${NC}" + find [0-9][0-9]* -type d | while read line + do + mkdir -p "../${lab}-${lang}/$line" + done + find [0-9][0-9]* -iname '*.md' | while read line + do + cp $line "../${lab}-${lang}/$line" + echo -e "\tvim ${lab}-${lang}/$line" + done + + find [0-9][0-9]* -type f -not -iname '*.md' | while read line + do + ln "../${lab}/$line" "../${lab}-${lang}/$line" + done + + cd - >/dev/null + + cp ${lab}/config.yml ${lab}-${lang}/ + + cp ${lab}/track.yml ${lab}-${lang}/ + if grep '^maintenance:' ${lab}-${lang}/track.yml >/dev/null + then + sed 's/^maintenance:.*/maintenance: true/' -i ${lab}-${lang}/track.yml + else + echo 'maintenance: true' >> ${lab}-${lang}/track.yml + fi + sed "s/^\(slug\)\(.*\)/\1\2-${lang}/i;s/^\(title\)\(.*\)/\1\2 - ${lang^^}/i" -i ${lab}-${lang}/track.yml + + echo -e "${PROGRESS}Change the variables inside config.yml if you wish to personalize it, otherwise just copy it as it is${NC} + \tvim ${lab}-${lang}/config.yml + ${PROGRESS}Change the description and other text for the lab found inside track.yml file${NC}: + \tvim ${lab}-${lang}/track.yml" + + echo -e "${PROGRESS}Adding it to git, please push your changes when they are ready for review${NC}" + git add ${lab}-${lang} + git commit ${lab}-${lang} -m "Added language \"${lang}\" for lab \"${lab}\", first commit" +else + lst_files='' + find ${lab} -iname 'assignment.md' -o -iname 'track.yml' -o -iname 'config.yml' | while read line + do + if [[ ! -f "${line/./-$lang.}" ]] + then + cp $line "${line/./-$lang.}" + echo -e "\tvim ${line/./-$lang.}" + if [[ "${line}" == "${lab}/track.yml" ]] + then + if grep '^maintenance:' ${lab}/track-${lang}.yml >/dev/null + then + sed 's/^maintenance:.*/maintenance: true/' -i ${lab}/track-${lang}.yml + else + echo 'maintenance: true' >> ${lab}/track-${lang}.yml + fi + sed "s/^\(slug\)\(.*\)/\1\2-${lang}/i;s/^\(title\)\(.*\)/\1\2 - ${lang^^}/i" -i ${lab}/track-${lang}.yml + fi + git add "${line/./-$lang.}" + lst_files="${line/./-$lang.} ${lst_files}" + else + echo "File already exists: ${line/./-$lang.}" + fi + done + + git commit -m "Added language \"${lang}\" for lab \"${lab}\", first commit" $lst_files +fi + diff --git a/scripts/smlm/generic_bootstrap.sh b/scripts/smlm/generic_bootstrap.sh new file mode 100644 index 0000000..0fa7fc8 --- /dev/null +++ b/scripts/smlm/generic_bootstrap.sh @@ -0,0 +1,953 @@ +#!/bin/bash + +# In case the script is executed using different interpreter than bash +# then we call the script explicitely using bash +SHPATH=$(readlink /proc/$$/exe) +if ! [ "$SHPATH" = "/bin/bash" -o "$SHPATH" = "/usr/bin/bash" ]; then + exec bash "$0" "$@" +fi + +echo "SUSE Manager Server Client bootstrap script v5.0.4" + +# This file was autogenerated. Minor manual editing of this script may be +# necessary to complete the bootstrap setup. Once customized, the bootstrap +# script can be triggered in one of two ways (the first is preferred): +# +# (1) centrally, from the SUSE Manager Server via ssh (i.e., from the +# SUSE Manager Server): +# cd /srv/www/htdocs/pub/bootstrap/ +# cat bootstrap-.sh | ssh root@ /bin/bash +# +# ...or... +# +# (2) in a decentralized manner, executed on each client, via wget or curl: +# wget -qO- https://mlm-server.geeko.land/pub/bootstrap/bootstrap-.sh | /bin/bash +# ...or... +# curl -Sks https://mlm-server.geeko.land/pub/bootstrap/bootstrap-.sh | /bin/bash + +# SECURITY NOTE: +# Use of these scripts via the two methods discussed is the most expedient +# way to register machines to your SUSE Manager Server. Since "wget" is used +# throughout the script to download various files, a "Man-in-the-middle" +# attack is theoretically possible. +# +# The actual registration process is performed securely via SSL, so the risk +# is minimized in a sense. This message merely serves as a warning. +# Administrators need to appropriately weigh their concern against the +# relative security of their internal network. + +# PROVISIONING/KICKSTART NOTE: +# If provisioning a client, ensure the proper CA SSL public certificate is +# configured properly in the post section of your kickstart profiles (the +# SUSE Manager Server or hosted web user interface). + +# REGISTER VERSIONING NOTE: +# This script will not work with traditional spacewalk registration tools. + + +echo +echo +echo "MINOR MANUAL EDITING OF THIS FILE MAY BE REQUIRED!" +echo +echo "If this bootstrap script was created during the initial installation" +echo "of a SUSE Manager Server, the ACTIVATION_KEYS, and ORG_GPG_KEY values will" +echo "probably *not* be set (see below). If this is the case, please do the" +echo "following:" +echo " - copy this file to a name specific to its use." +echo " (e.g., to bootstrap-SOME_NAME.sh - like bootstrap-web-servers.sh.)" +echo " - on the website create an activation key or keys for the system(s) to" +echo " be registered." +echo " - edit the values of the VARIABLES below (in this script) as" +echo " appropriate:" +echo " - ACTIVATION_KEYS needs to reflect the activation key(s) value(s)" +echo " from the website. XKEY or XKEY,YKEY" +echo " Please note that if you are using this script to boostrap minions," +echo " only the FIRST activation key will be used. Multiple activation keys" +echo " are not supported with salt" +echo " - ORG_GPG_KEY needs to be set to the name(s) of the corporate public" +echo " GPG key filename(s) (residing in /srv/www/htdocs/pub) if appropriate. XKEY or XKEY,YKEY" +echo " - When reactivating Salt minion, use REACTIVATION_KEY variable" +echo " Consider using environmental variable REACTIVATION_KEY for single use reactivation keys." +echo + + +echo "PROFILENAME ${PROFILENAME} ACTIVATION_KEYS=${ACTIVATION_KEYS} ORG_GPG_KEY=${ORG_GPG_KEY} SMLM_DNS=${SMLM_DNS} HOSTNAME=${HOSTNAME:-mlm-server.geeko.land} REACTIVATION_KEY=${REACTIVATION_KEY} CLIENT_OVERRIDES=${CLIENT_OVERRIDES:-client-config-overrides.txt} ORG_CA_CERT=${ORG_CA_CERT:-RHN-ORG-TRUSTED-SSL-CERT} USING_SSL=${USING_SSL:-1} USING_GPG=${USING_GPG:-1}" +# can be edited, but probably correct (unless created during initial install): +# NOTE: ACTIVATION_KEYS *must* be used to bootstrap a client machine. +ACTIVATION_KEYS=${ACTIVATION_KEYS} +ORG_GPG_KEY=${ORG_GPG_KEY} + +# To reactivate single Salt client use following variable: +# NOTE: Reactivation keys are removed valid only for single use. +# It is also possible to use REACTIVATION_KEY environmental variable. +REACTIVATION_KEY=${REACTIVATION_KEY} + +# can be edited, but probably correct: +CLIENT_OVERRIDES=${CLIENT_OVERRIDES:-client-config-overrides.txt} +if [[ "$SMLM_DNS" == "" ]] +then + HOSTNAME=${HOSTNAME:-mlm-server.geeko.land} +else + HOSTNAME="${SMLM_DNS}" +fi +ORG_CA_CERT=${ORG_CA_CERT:-RHN-ORG-TRUSTED-SSL-CERT} + +USING_SSL=${USING_SSL:-1} +USING_GPG=${USING_GPG:-1} + +REGISTER_THIS_BOX=${REGISTER_THIS_BOX:-1} + +# Set if you want to specify profilename for client systems. +# NOTE: Make sure it's set correctly if any external command is used. +# +# ex. PROFILENAME="foo.example.com" # For specific client system +# PROFILENAME=`hostname -s` # Short hostname +# PROFILENAME=`hostname -f` # FQDN +PROFILENAME="${PROFILENAME}" # Empty by default to let it be set automatically. + +# SUSE Manager Specific settings: +# +# - Alternate location of the client tool repos providing +# packages required for registration. Unless they are already installed on the +# client this repo is expected to provide them: +# ${CLIENT_REPOS_ROOT}/sle/VERSION/PATCHLEVEL +# If empty, the SUSE Manager repositories provided at https://${HOSTNAME}/pub/repositories +# are used. +CLIENT_REPOS_ROOT=${CLIENT_REPOS_ROOT} + +# Avoid installing venv-salt-minion instead salt-minion +# even if it available in the bootstrap repo +AVOID_VENV_SALT_MINION=${AVOID_VENV_SALT_MINION:-0} + +# Force installing venv-salt-minion instead salt-minion +# even if it is NOT available in the bootstrap repo +FORCE_VENV_SALT_MINION=${FORCE_VENV_SALT_MINION:-0} + + +# Automatically schedule reboot of the machine in case of running transactional +# system (for example SLE Micro) +SCHEDULE_REBOOT_AFTER_TRANSACTION=${SCHEDULE_REBOOT_AFTER_TRANSACTION:-1} + +# +# ----------------------------------------------------------------------------- +# DO NOT EDIT BEYOND THIS POINT ----------------------------------------------- +# ----------------------------------------------------------------------------- +# + +VENV_ENABLED=0 + +# +# do not try to register a SUSE Manager server at itself +# +MYNAME=`hostname -f` +LCMYNAME=`echo $MYNAME | tr '[:upper:]' '[:lower:]'` +LCHOSTNAME=`echo $HOSTNAME | tr '[:upper:]' '[:lower:]'` + +if [ "$LCMYNAME" == "$LCHOSTNAME" ]; then + echo "Name of client and of SUSE Manager server are the same." + echo "Do not try to register a SUSE Manager server at itself!" + echo "Aborting." + exit 1 +fi + +# an idea from Erich Morisse (of Red Hat). +# use either wget *or* curl +# Also check to see if the version on the +# machine supports the insecure mode and format +# command accordingly. + +if [ -x /usr/bin/wget ]; then + output=`LANG=en_US /usr/bin/wget --no-check-certificate 2>&1` + error=`echo $output | grep "unrecognized option"` + if [ -z "$error" ]; then + FETCH="/usr/bin/wget -nv -r -nd --no-check-certificate" + else + FETCH="/usr/bin/wget -nv -r -nd" + fi +elif [ -x /usr/bin/curl ]; then + output=`LANG=en_US /usr/bin/curl -k 2>&1` + error=`echo $output | grep "is unknown"` + if [ -z "$error" ]; then + FETCH="/usr/bin/curl -ksSOf" + else + FETCH="/usr/bin/curl -sSOf" + fi +else + echo "To be able to download files, please install either 'wget' or 'curl'" + exit 1 +fi + +HTTP_PUB_DIRECTORY=http://${HOSTNAME}/pub +HTTPS_PUB_DIRECTORY=https://${HOSTNAME}/pub +if [ $USING_SSL -eq 0 ]; then + HTTPS_PUB_DIRECTORY=${HTTP_PUB_DIRECTORY} +fi + +INSTALLER=zypper + +# the order matters: see bsc#1222347 +if [ -x /usr/bin/dnf ]; then + INSTALLER=yum +elif [ -x /usr/bin/yum ]; then + INSTALLER=yum +elif [ -x /usr/bin/zypper ]; then + INSTALLER=zypper +elif [ -x /usr/bin/apt ]; then + INSTALLER=apt +fi + + +SNAPSHOT_ID="" + +function call_tukit() { + tukit -q call $SNAPSHOT_ID /bin/bash <<< $@ +} + +function new_transaction() { + if [ -n "$SNAPSHOT_ID" ]; then + tukit -q close $SNAPSHOT_ID + fi + SNAPSHOT_ID=$(/usr/sbin/tukit -q open | sed 's/ID: \([0-9]*\)/\1/') + if [ -z "$SNAPSHOT_ID" ]; then + echo "Transactional system detected, but could not open new transaction. Aborting!" + exit 1 + fi +} + +if [ -x /usr/sbin/tukit ]; then + new_transaction + echo "Transactional system detected. Reboot will be required to finish bootstrapping" +fi + +if [ ! -w . ]; then + echo "" + echo "*** ERROR: $(pwd):" + echo " No permission to write to the current directory." + echo " Please execute this script in a directory where downloaded files can be stored." + echo "" + exit 1 +fi +echo +echo "PREPARE GPG KEYS AND CORPORATE PUBLIC CA CERT" +echo "-------------------------------------------------" +if [ ! -z "$ORG_GPG_KEY" ]; then + echo + echo "* importing organizational GPG keys" + for GPG_KEY in $(echo "$ORG_GPG_KEY" | tr "," " "); do + rm -f ${GPG_KEY} + $FETCH ${HTTPS_PUB_DIRECTORY}/${GPG_KEY} + if [ "$INSTALLER" == "apt" ]; then + apt-get --yes install --no-install-recommends gnupg + apt-key add $GPG_KEY + else + rpm --import $GPG_KEY + fi + rm -f ${GPG_KEY} + done +else + echo "* no organizational GPG keys to import" +fi + +echo + if [ "$INSTALLER" == "apt" ]; then + CERT_DIR=/usr/local/share/ca-certificates/susemanager + TRUST_DIR=/usr/local/share/ca-certificates/susemanager + UPDATE_TRUST_CMD="/usr/sbin/update-ca-certificates" + ORG_CA_CERT=RHN-ORG-TRUSTED-SSL-CERT + else + CERT_DIR=/usr/share/rhn + TRUST_DIR=/etc/pki/ca-trust/source/anchors + UPDATE_TRUST_CMD="/usr/bin/update-ca-trust extract" + fi + + if [ "$INSTALLER" == "apt" ]; then + CERT_FILE="${ORG_CA_CERT}.crt" + else + CERT_FILE=${ORG_CA_CERT} + fi + + function updateCertificates() { + if [ -d /etc/pki/ca-trust/source/anchors -a -x /usr/bin/update-ca-trust ]; then + TRUST_DIR=/etc/pki/ca-trust/source/anchors + elif [ -d /etc/pki/trust/anchors/ -a -x /usr/sbin/update-ca-certificates ]; then + # SLE 12 + TRUST_DIR=/etc/pki/trust/anchors + UPDATE_TRUST_CMD="/usr/sbin/update-ca-certificates" + elif [ -d /etc/ssl/certs -a -x /usr/bin/c_rehash -a "$INSTALLER" == "zypper" ]; then + # SLE 11 + TRUST_DIR=/etc/ssl/certs + UPDATE_TRUST_CMD="/usr/bin/c_rehash" + rm -f $TRUST_DIR/RHN-ORG-TRUSTED-SSL-CERT.pem + rm -f $TRUST_DIR/RHN-ORG-TRUSTED-SSL-CERT-*.pem + if [ -f $CERT_DIR/$CERT_FILE ]; then + ln -sf $CERT_DIR/$CERT_FILE $TRUST_DIR/RHN-ORG-TRUSTED-SSL-CERT.pem + if [ $(grep -- "-----BEGIN CERTIFICATE-----" $CERT_DIR/$CERT_FILE | wc -l) -gt 1 ]; then + csplit -b "%02d.pem" -f $TRUST_DIR/RHN-ORG-TRUSTED-SSL-CERT- $CERT_DIR/$CERT_FILE '/-----BEGIN CERTIFICATE-----/' '{*}' + fi + fi + $UPDATE_TRUST_CMD >/dev/null + return + fi + + if [ ! -d $TRUST_DIR ]; then + return + fi + if [ "$CERT_DIR" != "$TRUST_DIR" ]; then + if [ -z "$SNAPSHOT_ID" ]; then + if [ -f $CERT_DIR/$CERT_FILE ]; then + ln -sf $CERT_DIR/$CERT_FILE $TRUST_DIR + else + rm -f $TRUST_DIR/$CERT_FILE + fi + else + if call_tukit "test -f '$CERT_DIR/$CERT_FILE'"; then + call_tukit "ln -sf '$CERT_DIR/$CERT_FILE' '$TRUST_DIR'" + else + call_tukit "rm -f '$TRUST_DIR/$CERT_FILE'" + fi + fi + fi + $UPDATE_TRUST_CMD + } + + echo "* attempting to install corporate public CA cert" + + ### Check for Dynamic CA-Trust Updates - applies to RedHat and SLE-ES systems ### + if [ -x /usr/bin/update-ca-trust ]; then + if [ "$(/usr/bin/update-ca-trust check | grep 'PEM/JAVA Status: DISABLED')" != "" ]; then + echo "ERROR: Dynamic CA-Trust > Updates are disabled. Enable Dynamic CA-Trust Updates with '/usr/bin/update-ca-trust force-enable'" + echo "Finally, restart the onboarding sequence." + exit 1 + fi + fi + + rm -f ${ORG_CA_CERT} + $FETCH ${HTTPS_PUB_DIRECTORY}/${ORG_CA_CERT} + + if [ -n "$SNAPSHOT_ID" ]; then + # we need to copy certificate to the trustroot outside of transaction for zypper + cp "$ORG_CA_CERT" /etc/pki/trust/anchors/ + call_tukit "test -d '$CERT_DIR' || mkdir -p '$CERT_DIR'" + call_tukit "cp '/etc/pki/trust/anchors/$ORG_CA_CERT' '${CERT_DIR}/${CERT_FILE}'" + else + test -d "$CERT_DIR" || mkdir -p "$CERT_DIR" + mv "$ORG_CA_CERT" "${CERT_DIR}/${CERT_FILE}" + fi + echo "* update certificates" + updateCertificates +echo +echo "CLEANING UP OLD SUSE MANAGER REPOSITORIES" +echo "-------------------------------------------------" + +function clean_up_old_trad_repos() { + local trad_client_repo_prefix="spacewalk:" + if [ -f /usr/bin/realpath ]; then + GET_PATH="/usr/bin/realpath" + else + GET_PATH="/usr/bin/readlink -f --" + fi + + for file in $1/$trad_client_repo_prefix*.repo; do + if [ -f "$file" ]; then + echo "Removing $($GET_PATH "$file")" + rm -f $($GET_PATH "$file") + fi + done +} + +function clean_up_old_salt_repos() { + if [ -f "$1" ]; then + echo "Removing $1" + rm -f "$1" + fi +} + +function clean_up_old_repos() { + clean_up_old_salt_repos "/etc/zypp/repos.d/susemanager:channels.repo" + clean_up_old_salt_repos "/etc/yum.repos.d/susemanager:channels.repo" + clean_up_old_salt_repos "/etc/apt/sources.list.d/susemanager:channels.list" + + clean_up_old_trad_repos "/etc/zypp/repos.d" + clean_up_old_trad_repos "/etc/yum.repos.d" +} + +clean_up_old_repos +echo +echo "CHECKING THE REGISTRATION STACK" +echo "-------------------------------------------------" + +function test_repo_exists() { + local repourl="$CLIENT_REPO_URL" + + $FETCH $repourl/repodata/repomd.xml + if [ ! -f "repomd.xml" ]; then + echo "Bootstrap repo '$repourl' does not exist." + repourl="" + CLIENT_REPO_URL="" + fi + rm -f repomd.xml +} + +function test_venv_enabled() { + if [ $FORCE_VENV_SALT_MINION -eq 1 ]; then + VENV_ENABLED=1 + elif [ $AVOID_VENV_SALT_MINION -ne 1 ]; then + local repourl="$CLIENT_REPO_URL" + if [ "$INSTALLER" == "zypper" ] || [ "$INSTALLER" == "yum" ]; then + ARCH=$(rpm --eval "%{_arch}") + else + ARCH=$(dpkg --print-architecture) + fi + VENV_FILE="venv-enabled-$ARCH.txt" + $FETCH $repourl/$VENV_FILE + if [ -f "$VENV_FILE" ]; then + echo "Bootstrap repo '$repourl' contains salt bundle." + repourl="" + VENV_ENABLED=1 + fi + rm -f "$VENV_FILE" + fi +} + + +function setup_bootstrap_repo() { + local repopath="$CLIENT_REPO_FILE" + local reponame="$CLIENT_REPO_NAME" + local repourl="$CLIENT_REPO_URL" + + test_repo_exists + + if [ -n "$CLIENT_REPO_URL" ]; then + echo " adding client software repository at $repourl" + cat <"$repopath" +[$reponame] +name=$reponame +baseurl=$repourl +enabled=1 +autorefresh=1 +keeppackages=0 +gpgcheck=0 +EOF + fi + + # Avoid modularity failsafe mechanism in dnf 4.2.7 or greater + if [ -n "$Y_CLIENT_CODE_VERSION" ] && [ $Y_CLIENT_CODE_VERSION -ge 8 ]; then + echo " adding 'module_hotfixes' flag to the repository config" + echo "module_hotfixes=1" >> "$repopath" + fi +} + +function remove_bootstrap_repo() { + local repopath="$CLIENT_REPO_FILE" + + rm -f $repopath +} + +if [ "$INSTALLER" == yum ]; then + function getY_CLIENT_CODE_BASE() { + local BASE="" + local VERSION="" + # SLES ES6 is a special case; it will install a symlink named + # centos-release pointing to redhat-release which will make the + # original test fail; reverting the checks does not help as this + # will break genuine CentOS systems. So use the poor man's approach + # to detect this special case. SLES ES7 does not have this issue + # https://bugzilla.suse.com/show_bug.cgi?id=1132576 + # https://bugzilla.suse.com/show_bug.cgi?id=1152795 + if [ -L /usr/share/doc/sles_es-release ]; then + BASE="res" + VERSION=6 + elif [ -f /etc/almalinux-release ]; then + grep -v '^#' /etc/almalinux-release | grep -q '\(AlmaLinux\)' && BASE="almalinux" + VERSION=`grep -v '^#' /etc/almalinux-release | grep -Po '(?<=release )\d+'` + elif [ -f /etc/rocky-release ]; then + grep -v '^#' /etc/rocky-release | grep -q '\(Rocky Linux\)' && BASE="rockylinux" + VERSION=`grep -v '^#' /etc/rocky-release | grep -Po '(?<=release )\d+'` + elif [ -f /etc/oracle-release ]; then + grep -v '^#' /etc/oracle-release | grep -q '\(Oracle\)' && BASE="oracle" + VERSION=`grep -v '^#' /etc/oracle-release | grep -Po '(?<=release )\d+'` + elif [ -f /etc/alinux-release ]; then + grep -v '^#' /etc/alinux-release | grep -q '\(Alibaba\)' && BASE="alibaba" + VERSION=`grep -v '^#' /etc/alinux-release | grep -Po '(?<=release )\d+'` + elif [ -f /etc/centos-release ]; then + grep -v '^#' /etc/centos-release | grep -q '\(CentOS\)' && BASE="centos" + VERSION=`grep -v '^#' /etc/centos-release | grep -Po '(?<=release )\d+'` + elif [ -f /etc/redhat-release ]; then + grep -v '^#' /etc/redhat-release | grep -q '\(Red Hat\)' && BASE="res" + VERSION=`grep -v '^#' /etc/redhat-release | grep -Po '(?<=release )\d+'` + elif [ -f /etc/openEuler-release ]; then + grep -v '^#' /etc/openEuler-release | grep -q '\(openEuler\)' && BASE="openEuler" + VERSION=`grep -v '^#' /etc/openEuler-release | grep -Po '(?<=release )(\d+\.)+\d+'` + elif [ -f /etc/os-release ]; then + BASE=$(source /etc/os-release; echo $ID) + VERSION=$(source /etc/os-release; echo $VERSION_ID) + fi + Y_CLIENT_CODE_BASE="${BASE:-unknown}" + Y_CLIENT_CODE_VERSION="${VERSION:-unknown}" + } + + function getY_MISSING() { + local NEEDED="salt salt-minion" + if [ $VENV_ENABLED -eq 1 ]; then + NEEDED="venv-salt-minion" + fi + Y_MISSING="" + for P in $NEEDED; do + rpm -q "$P" || Y_MISSING="$Y_MISSING $P" + done + } + + echo "* check for necessary packages being installed..." + getY_CLIENT_CODE_BASE + echo "* client codebase is ${Y_CLIENT_CODE_BASE}-${Y_CLIENT_CODE_VERSION}" + + CLIENT_REPOS_ROOT="${CLIENT_REPOS_ROOT:-https://${HOSTNAME}/pub/repositories}" + CLIENT_REPO_URL="${CLIENT_REPOS_ROOT}/${Y_CLIENT_CODE_BASE}/${Y_CLIENT_CODE_VERSION}/bootstrap" + CLIENT_REPO_NAME="susemanager:bootstrap" + CLIENT_REPO_FILE="/etc/yum.repos.d/$CLIENT_REPO_NAME.repo" + + # In case of Red Hat derivatives, check if bootstrap repository is available, if not, fallback to RES. + if [ "$Y_CLIENT_CODE_BASE" == almalinux ] || [ "$Y_CLIENT_CODE_BASE" == rockylinux ] || [ "$Y_CLIENT_CODE_BASE" == oracle ] || [ "$Y_CLIENT_CODE_BASE" == alibaba ] || [ "$Y_CLIENT_CODE_BASE" == openEuler ] || [ "$Y_CLIENT_CODE_BASE" == centos ] ; then + $FETCH $CLIENT_REPO_URL/repodata/repomd.xml &> /dev/null + if [ $? -ne 0 ]; then + echo "${Y_CLIENT_CODE_BASE} ${Y_CLIENT_CODE_VERSION} bootstrap repository not found, using RES${Y_CLIENT_CODE_VERSION} bootstrap repository instead" + CLIENT_REPO_URL="${CLIENT_REPOS_ROOT}/res/${Y_CLIENT_CODE_VERSION}/bootstrap" + fi + fi + + setup_bootstrap_repo + + test_venv_enabled + + getY_MISSING + + if [ -z "$Y_MISSING" ]; then + echo " no packages missing." + else + echo "* going to install missing packages..." + + yum -y install $Y_MISSING + + for P in $Y_MISSING; do + rpm -q "$P" || { + echo "ERROR: Failed to install all missing packages." + exit 1 + } + done + fi + # try update main packages for registration from any repo which is available + if [ $VENV_ENABLED -eq 1 ]; then + yum -y upgrade venv-salt-minion yum openssl ||: + else + yum -y upgrade salt salt-minion yum openssl $RHNLIB_PKG ||: + fi + +elif [ "$INSTALLER" == zypper ]; then + function getZ_CLIENT_CODE_BASE() { + local BASE="" + local VERSION="" + local PATCHLEVEL="" + if [ -r /etc/SuSE-release ]; then + grep -q 'Enterprise' /etc/SuSE-release && BASE='sle' + eval $(grep '^\(VERSION\|PATCHLEVEL\)' /etc/SuSE-release | tr -d '[:blank:]') + if [ "$BASE" != "sle" ]; then + grep -q 'openSUSE' /etc/SuSE-release && BASE='opensuse' + VERSION="$(grep '^\(VERSION\)' /etc/SuSE-release | tr -d '[:blank:]' | sed -n 's/.*=\([[:digit:]]\+\).*/\1/p')" + PATCHLEVEL="$(grep '^\(VERSION\)' /etc/SuSE-release | tr -d '[:blank:]' | sed -n 's/.*\.\([[:digit:]]*\).*/\1/p')" + fi + elif [ -r /etc/os-release ]; then + grep -q 'Enterprise' /etc/os-release && BASE='sle' + if [ "$BASE" != "sle" ]; then + grep -q 'openSUSE' /etc/os-release && BASE='opensuse' + fi + if [ "$BASE" == "" ]; then + grep -q 'cpe:/o:suse:' /etc/os-release && BASE='sl' + fi + grep -q 'Micro' /etc/os-release && BASE="${BASE}micro" + VERSION="$(grep '^\(VERSION_ID\)' /etc/os-release | sed -n 's/.*"\([[:digit:]]\+\).*/\1/p')" + PATCHLEVEL="$(grep '^\(VERSION_ID\)' /etc/os-release | sed -n 's/.*\.\([[:digit:]]*\).*/\1/p')" + # openSUSE MicroOS + grep -q 'MicroOS' /etc/os-release && BASE='opensusemicroos' && VERSION='latest' + # openSUSE Tumbleweed + grep -q 'Tumbleweed' /etc/os-release && BASE='opensusetumbleweed' && VERSION='latest' + fi + Z_CLIENT_CODE_BASE="${BASE:-unknown}" + Z_CLIENT_CODE_VERSION="${VERSION:-unknown}" + Z_CLIENT_CODE_PATCHLEVEL="${PATCHLEVEL:-0}" + } + + function getZ_MISSING() { + local NEEDED="salt salt-minion" + if [ $VENV_ENABLED -eq 1 ]; then + NEEDED="venv-salt-minion" + fi + if [ "$Z_CLIENT_CODE_BASE" == "sle" -a "$Z_CLIENT_CODE_VERSION" == "10" ]; then + # (bnc#789373) Code 10 product migration requires 'xsltproc' being installed + which 'xsltproc' || NEEDED="$NEEDED libxslt" + fi + Z_MISSING="" + for P in $NEEDED; do + rpm -q "$P" || Z_MISSING="$Z_MISSING $P" + done + } + + echo "* check for necessary packages being installed..." + # client codebase determines repo url to use and whether additional + # preparations are needed before installing the missing packages. + getZ_CLIENT_CODE_BASE + echo "* client codebase is ${Z_CLIENT_CODE_BASE}-${Z_CLIENT_CODE_VERSION}-sp${Z_CLIENT_CODE_PATCHLEVEL}" + + CLIENT_REPOS_ROOT="${CLIENT_REPOS_ROOT:-${HTTPS_PUB_DIRECTORY}/repositories}" + CLIENT_REPO_URL="${CLIENT_REPOS_ROOT}/${Z_CLIENT_CODE_BASE}/${Z_CLIENT_CODE_VERSION}/${Z_CLIENT_CODE_PATCHLEVEL}/bootstrap" + CLIENT_REPO_NAME="susemanager:bootstrap" + CLIENT_REPO_FILE="/etc/zypp/repos.d/$CLIENT_REPO_NAME.repo" + + test_venv_enabled + + getZ_MISSING + + if [ -z "$Z_MISSING" ]; then + echo " no packages missing." + setup_bootstrap_repo + else + echo "* going to install missing packages..." + + # Note: We try to install the missing packages even if adding the repo fails. + # Might be some other system repo provides them instead. + + setup_bootstrap_repo + + if [ -z "$SNAPSHOT_ID" ]; then + zypper --non-interactive --gpg-auto-import-keys refresh "$CLIENT_REPO_NAME" + # install missing packages + zypper --non-interactive in $Z_MISSING + for P in $Z_MISSING; do + rpm -q --whatprovides "$P" || { + echo "ERROR: Failed to install all missing packages." + exit 1 + } + done + else + call_tukit "zypper --non-interactive --gpg-auto-import-keys refresh '$CLIENT_REPO_NAME'" + if ! call_tukit "zypper --non-interactive install $Z_MISSING"; then + echo "ERROR: Failed to install all required packages." + tukit abort "$SNAPSHOT_ID" + exit 1 + fi + fi + fi + + # try update main packages for registration from any repo which is available + if [ $VENV_ENABLED -eq 1 ]; then + if [ -z "$SNAPSHOT_ID" ]; then + zypper --non-interactive up venv-salt-minion zypper openssl ||: + else + call_tukit "zypper --non-interactive update venv-salt-minion zypper openssl ||:" + fi + else + if [ -z "$SNAPSHOT_ID" ]; then + zypper --non-interactive up salt salt-minion zypper openssl $RHNLIB_PKG ||: + else + call_tukit "zypper --non-interactive update salt salt-minion zypper openssl $RHNLIB_PKG ||:" + fi + fi + +elif [ "$INSTALLER" == apt ]; then + function check_deb_pkg_installed { + dpkg-query -W -f='${Status}' $1 2>/dev/null | grep -q "ok installed" + } + + function getA_CLIENT_CODE_BASE() { + local BASE="" + local VERSION="" + local VARIANT_ID="" + + if [ -f /etc/os-release ]; then + BASE=$(source /etc/os-release; echo $ID) + VERSION=$(source /etc/os-release; echo $VERSION_ID) + VARIANT_ID=$(source /etc/os-release; echo $VARIANT_ID) + fi + A_CLIENT_CODE_BASE="${BASE:-unknown}" + local VERCOMPS=(${VERSION/\./ }) # split into an array 18.04 -> (18 04) + A_CLIENT_CODE_MAJOR_VERSION=${VERCOMPS[0]} + # Ubuntu only + if [ "${BASE}" == "ubuntu" ]; then + A_CLIENT_CODE_MINOR_VERSION=$((${VERCOMPS[1]} + 0)) # convert "04" -> 4 + fi + A_CLIENT_VARIANT_ID="${VARIANT_ID:-unknown}" + } + + function getA_MISSING() { + local NEEDED="salt-common salt-minion" + if [ $VENV_ENABLED -eq 1 ]; then + NEEDED="venv-salt-minion" + elif [[ $A_CLIENT_CODE_BASE == "ubuntu" && $A_CLIENT_CODE_MAJOR_VERSION == 18 ]]; then + # Ubuntu 18.04 needs these extra dependencies. They are not specified in + # python3-salt because we don't maintain multiple .deb build instructions + # and we can't add logic that adds the deps depending on which OS the .deb + # is built for. + NEEDED="$NEEDED python3-contextvars python3-immutables" + fi + A_MISSING="" + for P in $NEEDED; do + check_deb_pkg_installed "$P" || A_MISSING="$A_MISSING $P" + done + } + + function test_deb_repo_exists() { + local repourl="$CLIENT_REPO_URL" + + $FETCH $repourl/dists/bootstrap/Release + if [ ! -f "Release" ]; then + echo "Bootstrap repo '$repourl' does not exist." + repourl="" + CLIENT_REPO_URL="" + fi + rm -f Release + } + + function setup_deb_bootstrap_repo() { + local repopath="$CLIENT_REPO_FILE" + local repourl="$CLIENT_REPO_URL" + + test_deb_repo_exists + + if [ -n "$CLIENT_REPO_URL" ]; then + echo " adding client software repository at $repourl" + echo "deb [trusted=yes] $repourl bootstrap main" >"$repopath" + fi + } + + echo "* check for necessary packages being installed..." + getA_CLIENT_CODE_BASE + if [ "${A_CLIENT_CODE_BASE}" == "astra" ]; then + echo "* client codebase is ${A_CLIENT_CODE_BASE}-${A_CLIENT_VARIANT_ID}" + else + echo "* client codebase is ${A_CLIENT_CODE_BASE}-${A_CLIENT_CODE_MAJOR_VERSION}.${A_CLIENT_CODE_MINOR_VERSION}" + fi + + CLIENT_REPOS_ROOT="${CLIENT_REPOS_ROOT:-${HTTPS_PUB_DIRECTORY}/repositories}" + # Debian does not need minor version in the bootstrap repo URL + if [ "${A_CLIENT_CODE_BASE}" == "debian" ] || [ "${A_CLIENT_CODE_BASE}" == "raspbian" ]; then + CLIENT_REPO_URL="${CLIENT_REPOS_ROOT}/${A_CLIENT_CODE_BASE}/${A_CLIENT_CODE_MAJOR_VERSION}/bootstrap" + elif [ "${A_CLIENT_CODE_BASE}" == "astra" ]; then + CLIENT_REPO_URL="${CLIENT_REPOS_ROOT}/${A_CLIENT_CODE_BASE}/${A_CLIENT_VARIANT_ID}/bootstrap" + else + CLIENT_REPO_URL="${CLIENT_REPOS_ROOT}/${A_CLIENT_CODE_BASE}/${A_CLIENT_CODE_MAJOR_VERSION}/${A_CLIENT_CODE_MINOR_VERSION}/bootstrap" + fi + CLIENT_REPO_NAME="susemanager_bootstrap" + CLIENT_REPO_FILE="/etc/apt/sources.list.d/$CLIENT_REPO_NAME.list" + + setup_deb_bootstrap_repo + + test_venv_enabled + + getA_MISSING + + apt-get --yes update + + if [ -z "$A_MISSING" ]; then + echo " no packages missing." + else + echo "* going to install missing packages..." + # check if there are any leftovers from previous salt-minion installs and purge them + SALT_MINION_PKG="salt-minion" + if [ $VENV_ENABLED -eq 1 ]; then + SALT_MINION_PKG="venv-salt-minion" + fi + dpkg-query -W -f='${Status}' "$SALT_MINION_PKG" 2>/dev/null | grep -q "deinstall ok config-files" + if [ "$?" -eq 0 ]; then + echo "* purging previous Salt config files" + apt-get --yes purge "$SALT_MINION_PKG" + if [ $VENV_ENABLED -eq 1 ]; then + rm -rf /etc/venv-salt-minion/ + else + apt-get purge salt-common + rm -rf /etc/salt/minion.d/ + fi + fi + apt-get --yes install --no-install-recommends $A_MISSING + + for P in $A_MISSING; do + check_deb_pkg_installed "$P" || { + echo "ERROR: Failed to install all missing packages." + exit 1 + } + done + fi + # try update main packages for registration from any repo which is available + if [ $VENV_ENABLED -eq 1 ]; then + apt-get --yes install --no-install-recommends --only-upgrade venv-salt-minion ||: + else + apt-get --yes install --no-install-recommends --only-upgrade salt-common salt-minion ||: + fi + + # remove bootstrap repo + rm -f $CLIENT_REPO_FILE + +fi + +remove_bootstrap_repo + +function removeTLSCertificate() { + if [ "$INSTALLER" == "apt" ]; then + CERT_DIR=/usr/local/share/ca-certificates/susemanager + TRUST_DIR=/usr/local/share/ca-certificates/susemanager + UPDATE_TRUST_CMD="/usr/sbin/update-ca-certificates" + ORG_CA_CERT=RHN-ORG-TRUSTED-SSL-CERT + else + CERT_DIR=/usr/share/rhn + TRUST_DIR=/etc/pki/ca-trust/source/anchors + UPDATE_TRUST_CMD="/usr/bin/update-ca-trust extract" + fi + + if [ -f /usr/share/rhn/${ORG_CA_CERT} ]; then + CERT_FILE=${ORG_CA_CERT} + rm -f /usr/share/rhn/${ORG_CA_CERT} + elif [ -f /usr/local/share/ca-certificates/susemanager/${ORG_CA_CERT}.crt ]; then + CERT_FILE=${ORG_CA_CERT}.crt + rm -f /usr/local/share/ca-certificates/susemanager/${CERT_FILE} + fi + updateCertificates +} + +echo +echo "REGISTRATION" +echo "------------" +# Should have created an activation key or keys on the SUSE Manager Server's +# website and edited the value of ACTIVATION_KEYS above. +# +# If you require use of several different activation keys, copy this file and +# change the string as needed. +# + +if [[ $ACTIVATION_KEYS =~ , ]]; then + echo "*** ERROR: Multiple activation keys are not supported with salt!" + exit 1 +fi + +SNAPSHOT_PREFIX="" +if [ -n "$SNAPSHOT_ID" ]; then + SNAPSHOT_PREFIX="/var/lib/overlay/$SNAPSHOT_ID" +fi + +MINION_ID_FILE="${SNAPSHOT_PREFIX}/etc/salt/minion_id" +MINION_PKI_CONF="${SNAPSHOT_PREFIX}/etc/salt/pki/minion" +MINION_CONFIG_DIR="${SNAPSHOT_PREFIX}/etc/salt/minion.d" +SUSEMANAGER_MASTER_FILE="${MINION_CONFIG_DIR}/susemanager.conf" +MINION_SERVICE="salt-minion" + +if [ $VENV_ENABLED -eq 1 ]; then + MINION_ID_FILE="${SNAPSHOT_PREFIX}/etc/venv-salt-minion/minion_id" + MINION_PKI_CONF="${SNAPSHOT_PREFIX}/etc/venv-salt-minion/pki/minion" + MINION_CONFIG_DIR="${SNAPSHOT_PREFIX}/etc/venv-salt-minion/minion.d" + SUSEMANAGER_MASTER_FILE="${MINION_CONFIG_DIR}/susemanager.conf" + MINION_SERVICE="venv-salt-minion" +fi + +if [ $REGISTER_THIS_BOX -eq 1 ]; then + echo "* registering" + + PREV_MASTER="$(sed -n 's/^master: //p' $SUSEMANAGER_MASTER_FILE 2> /dev/null)" + # Remove old minion keys so reregistration do different master works + # Delete the pki config only in case of changing the master + if [ -d "$MINION_PKI_CONF" -a "$HOSTNAME" != "$PREV_MASTER" ]; then + echo "* removing old Salt PKI files" + rm -r "$MINION_PKI_CONF" + fi + + if [ -n "$PROFILENAME" ]; then + echo "$PROFILENAME" > "$MINION_ID_FILE" + else + echo "$MYNAME" > "$MINION_ID_FILE" + fi + cat < "$SUSEMANAGER_MASTER_FILE" +master: $HOSTNAME +server_id_use_crc: adler32 +enable_legacy_startup_events: False +enable_fqdns_grains: False +start_event_grains: [machine_id, saltboot_initrd, susemanager] +mine_enabled: False +EOF + cat <> "$SUSEMANAGER_MASTER_FILE" + +grains: + susemanager: +EOF + if [ -n "$ACTIVATION_KEYS" ]; then + echo "Using activation key: "$ACTIVATION_KEYS" with configuration file $SUSEMANAGER_MASTER_FILE" + cat <>"$SUSEMANAGER_MASTER_FILE" + activation_key: "$(echo $ACTIVATION_KEYS | cut -d, -f1)" +EOF + fi + if [ -n "$REACTIVATION_KEY" ]; then + echo "Using reactivation key: "$REACTIVATION_KEY" with configuration file $SUSEMANAGER_MASTER_FILE" + cat <>"$SUSEMANAGER_MASTER_FILE" + management_key: "$(echo $REACTIVATION_KEY)" +EOF + fi + if [ -n "$PROFILENAME" ]; then + echo "Setting profile name to: $PROFILENAME with configuration file $SUSEMANAGER_MASTER_FILE" + cat <>"$SUSEMANAGER_MASTER_FILE" + profile_name: "$(echo $PROFILENAME)" +EOF + + fi + cat <> "$SUSEMANAGER_MASTER_FILE" + +system-environment: + modules: + pkg: + _: + SALT_RUNNING: 1 +EOF + +if [ -n "$SNAPSHOT_ID" ]; then + cat <> "${MINION_CONFIG_DIR}/transactional_update.conf" +# Enable the transactional_update executor +module_executors: + - transactional_update + - direct_call +# Include beacon to check for pending transactions indicating that a reboot is necessary +beacons: + reboot_info: + - interval: 10 +EOF + + if ! test -f /etc/transactional-update.conf; then + cp /usr/etc/transactional-update.conf /etc/transactional-update.conf + fi + + . /etc/transactional-update.conf + if [ -z "$REBOOT_METHOD" ] || [ "$REBOOT_METHOD" = "auto" ]; then + sed -i '/^REBOOT_METHOD=/d' /etc/transactional-update.conf + echo "REBOOT_METHOD=systemd" >> /etc/transactional-update.conf + fi + +fi # -n SNAPSHOT_ID +fi # REGISTER_THIS_BOX eq 1 + +echo "* removing TLS certificate used for bootstrap" +echo " (will be re-added via salt state)" + +removeTLSCertificate + +echo "* starting salt daemon and enabling it during boot" + +if [ -n "$SNAPSHOT_ID" ]; then + call_tukit "systemctl enable '$MINION_SERVICE'" + tukit -q close $SNAPSHOT_ID + if [ "$SCHEDULE_REBOOT_AFTER_TRANSACTION" -eq 1 ]; then + transactional-update reboot + else + echo "** Reboot system to apply changes" + fi +elif [ -f /usr/lib/systemd/system/$MINION_SERVICE.service ] || [ -f /lib/systemd/system/$MINION_SERVICE.service ]; then + systemctl enable $MINION_SERVICE + systemctl restart $MINION_SERVICE +else + /etc/init.d/$MINION_SERVICE restart + /sbin/chkconfig --add $MINION_SERVICE +fi +echo "-bootstrap complete-" + diff --git a/scripts/smlm/manage_activationkeys.py b/scripts/smlm/manage_activationkeys.py new file mode 100644 index 0000000..14ba44a --- /dev/null +++ b/scripts/smlm/manage_activationkeys.py @@ -0,0 +1,262 @@ +#!/usr/bin/python3 +# +# Authors: Raul Mahiques +# License: GPLv3 +# +# $Id$ +# + +from xmlrpc.client import ServerProxy +import ssl, argparse, yaml + + + +def smlm_login(server, user, pwd): + """ + Performs an authentication login and returns the session key + """ + context = ssl._create_unverified_context() + client = ServerProxy('https://' + server + '/rpc/api', context=context) + key = client.auth.login(user, pwd) + return key, client + + +def smlm_logout(key, client): + """ + Performs a logout + """ + client.auth.logout(key) + + +def smlm_create_ak(key, client, name, description, baseChannelLabel, usageLimit, entitlements , universalDefault, appstreams, childchannels, configchannels, packages, servergroups): + """ + Creates an activation key in SMLM + """ + akname = client.activationkey.create(key, name, description, baseChannelLabel, usageLimit, entitlements , universalDefault) + print('Activation Key ID: ' + akname) + if appstreams != []: + smlm_add_appstreams_akid(key, client, akname, appstreams.split(',')) + if childchannels != []: + smlm_add_childchannels_akid(key, client, akname, childchannels.split(',')) + if configchannels != []: + smlm_add_configchannels_akid(key, client, akname, configchannels.split(',')) + if packages != []: + smlm_add_packages_akid(key, client, akname, packages.split(',')) + if servergroups != []: + smlm_add_servergroups_akid(key, client, akname, servergroups.split(',')) + +def smlm_get_ak(key, client, akname): + """ + Returns information about an Activation Key in SMLM + """ + print(yaml.dump(client.activationkey.getDetails(key, akname))) + + +def smlm_list_aks(key, client): + """ + Returns the list of Activation Key in SMLM + """ + return client.activationkey.listActivationKeys(key) + + +def smlm_get_akid(key, client, akname): + """ + Retrieves information about a SMLM Activation Key and returns the Activation Key ID. + """ + akDetails = client.activationkey.getDetails(key, akname) + print(akDetails) + + +def smlm_del_ak(key, client, akid): + """ + Deletes an Activation Key from SMLM + """ + print(akid) + result = client.activationkey.delete(key, akid) + print('Results:\n', result) + + +def smlm_add_appstreams_akid(key, client, akname, appstreams): + """ + Add to a SMLM Activation Key. + """ + akDetails = client.activationkey.addAppStreams(key, akname, appstreams) + + +def smlm_add_childchannels_akid(key, client, akname, childchannels): + """ + Add Child Channels to a SMLM Activation Key. + """ + akDetails = client.activationkey.addChildChannels(key, akname, childchannels) + + + + +def smlm_add_configchannels_akid(key, client, akname, configchannels): + """ + Add Config Channels to a SMLM Activation Key. + """ + akDetails = client.activationkey.addConfigChannels(key, akname, configchannels) + + +def smlm_add_entitlements_akid(key, client, akname, entitlements): + """ + Add Entitlements to a SMLM Activation Key. + """ + akDetails = client.activationkey.addEntitlements(key, akname, entitlements) + + +def smlm_add_packages_akid(key, client, akname, packages): + """ + Add Packages to a SMLM Activation Key. + """ + akDetails = client.activationkey.addPackages(key, akname, packages) + + +def smlm_add_servergroups_akid(key, client, akname, servergroups): + """ + Add Server Groups to a SMLM Activation Key. + """ + akDetails = client.activationkey.addServerGroups(key, akname, servergroups) + + + +#### List methods +def smlm_list_appstreams(key, client, channellabel): + """ + List Appstreams from SMLM. + """ + return(client.channel.appstreams.listModuleStreams(key, channelLabel)) + + +def smlm_list_channels(key, client): + """ + List Main Channels from SMLM. + """ + return(client.channel.listAllChannels(key)) + +def smlm_list_childchannels(key, client): + """ + List Child Channels from SMLM. + """ + return(client.channel.listSoftwareChannels(key)) + +def smlm_list_configchannels(key, client): + """ + List Config Channels from SMLM. + """ + return(client.configchannel.listGlobals(key)) + + +def smlm_list_packages(key, client, channel): + """ + List Packages from SMLM channel. + """ + return client.channel.software.listAllPackages(key, channel) + + +def smlm_list_servergroups(key, client): + """ + List Server Groups from SMLM. + """ + return client.systemgroup.listAllGroups(key) + + + + + +def main(): + """ + Main function that parses the command-line arguments and initiate the API calls. + """ + # Define how we want to process command line arguments + parser = argparse.ArgumentParser(prog='smlm_ak',description='Manages SMLM Activation keys') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-a','--add', action='store_true', help='Add Activation Key') + group.add_argument('-d','--delete', action='store_true', help='Delete Activation Keys') + group.add_argument('-g','--get', action='store_true', help='Retrieve Activation Keys information') + group.add_argument('--list_appstreams', action='store_true', help='List App Streams') + group.add_argument('--list_childchannels', action='store_true', help='List Channels') + group.add_argument('--list_configchannels', action='store_true', help='List Config Channels') + group.add_argument('--list_packages', action='store_true', help='List Packages') + group.add_argument('--list_servergroups', action='store_true', help='List Server Groups ') + group.add_argument('-l','--list', action='store_true', help='List Activation Keys') + parser.add_argument('-u', '--user', type=str, required=True, help='User name with privileges to create Activation Keys') + parser.add_argument('-p', '--pwd', type=str, required=True, help='Password for user') + parser.add_argument('-s', '--server', type=str, required=True, help='Server FQDN') + parser.add_argument('-k','--akname', type=str, help='Activation Keys name. Must meet same criteria as in the web UI.') + parser.add_argument('--description', type=str, help='Activation Key description.') + parser.add_argument('--basechannellabel', type=str, help='Base Channel Label.') + parser.add_argument('--usagelimit', type=int, help="Number of systems that can use this, leave it empty for unlimited") + parser.add_argument('--entitlements', type=str, help="Entitlements separated by comma: container_build_host,monitoring_entitled,osimage_build_host,virtualization_host,ansible_control_node,proxy_entitled,") + parser.add_argument('--universal', action='store_true', help='Makes this activation key the universal default.') + parser.add_argument('--appstreams', type=str, help='Add app streams to an activation key. Separated by comma: aa,bb,cc') + parser.add_argument('--childchannels', type=str, help='Child channel/s. Separated by comma: aa,bb,cc') + parser.add_argument('--configchannels', type=str, help='Configuration channel/s. Separated by comma: aa,bb,cc') + parser.add_argument('--packages', type=str, help='Package/s. Separated by comma: aa,bb,cc') + parser.add_argument('--servergroups', type=str, help='Server group/s. Separated by comma: aa,bb,cc') + parser.add_argument('--debug', action='store_true', help="Use it to enable debug messages.") + inputparam=parser.parse_args() + + context = ssl._create_unverified_context() + client = ServerProxy('https://' + inputparam.server + '/rpc/api', context=context) + + key, client = smlm_login(inputparam.server, inputparam.user, inputparam.pwd) + + if(inputparam.add and inputparam.akname and inputparam.description and inputparam.basechannellabel): + print("Adding activation key " + str(inputparam.akname)) + smlm_create_ak(key, client, inputparam.akname, inputparam.description, inputparam.basechannellabel or '', inputparam.usagelimit or 0, inputparam.entitlements or [], inputparam.universal or False, inputparam.appstreams or [], inputparam.childchannels or [], inputparam.configchannels or [], inputparam.packages or [], inputparam.servergroups or []) + elif(inputparam.delete): + print("Deleting activation key " + str(inputparam.akname)) + smlm_del_ak(key, client, inputparam.akname) + elif(inputparam.get): + print("Retrieving information about activation key: " + str(inputparam.akname)) + print(str(smlm_get_ak(key, client, inputparam.akname))) + elif(inputparam.list): + print("Retrieving the list of Activation Keys") + print(yaml.dump(smlm_list_aks(key, client))) + elif(inputparam.list_appstreams): + print("Retrieving the list of App. Streams ") + if inputparam.basechannellabel: + print(yaml.dump(smlm_list_appstreams(key, client, inputparam.basechannellabel))) + else: + print("Missing --basechannellabel, use --list_channels to retrieve the list of channels") + elif(inputparam.list_childchannels): + print("Retrieving the list of Child channels") + smlm_channels = smlm_list_channels(key, client) + smlm_softwarechannels = smlm_list_childchannels(key, client) + for i in smlm_channels: + found = False + for chnl in smlm_softwarechannels: + if chnl['label'] == i["label"] and chnl['parent_label'] != '': + found = True + break + if found == False: + print("MAIN CHANNEL " + i["label"]) + for o in smlm_softwarechannels: + if o["parent_label"] == i["label"]: + print("\t- " + o["label"]) + elif(inputparam.list_configchannels): + print("Retrieving the list of Config Channels") + print(yaml.dump(smlm_list_configchannels(key, client))) + elif(inputparam.list_packages): + print("Retrieving the list of Packages") + if inputparam.basechannellabel: + print(yaml.dump(smlm_list_packages(key, client, inputparam.basechannellabel))) + else: + print("Missing basechannellabel parameter indicating the channel") + elif(inputparam.list_servergroups): + print("Retrieving the list of Server Groups") + print(yaml.dump(smlm_list_servergroups(key, client))) + else: + print("Invalid or missing parameters") + if(inputparam.debug): + print(yaml.dump(inputparam)) + + smlm_logout(key, client) + + + +if __name__ == '__main__': + main() + diff --git a/scripts/smlm/manage_custominfo.py b/scripts/smlm/manage_custominfo.py new file mode 100644 index 0000000..54e3cdd --- /dev/null +++ b/scripts/smlm/manage_custominfo.py @@ -0,0 +1,115 @@ +#!/usr/bin/python3 +# +# Author/s: Raul Mahiques +# License: GPLv3 +# +# $Id$ +# + +from xmlrpc.client import ServerProxy +import ssl, argparse, yaml, sys + + + +def smlm_login(server, user, pwd): + """ + Performs an authentication login and returns the session key + """ + context = ssl._create_unverified_context() + client = ServerProxy('https://' + server + '/rpc/api', context=context) + key = client.auth.login(user, pwd) + return key, client + + +def smlm_logout(key, client): + """ + Performs a logout + """ + client.auth.logout(key) + + +def smlm_create_key(key, client, keyLabel, keyDescription=None): + """ + Create a new custom key + """ + if(keyDescription == None): + keyDescription="Key "+name + + customkey = client.system.custominfo.createKey(key, keyLabel, keyDescription) + return customkey + + +def smlm_delete_key(key, client, keyLabel): + """ + Delete an existing custom key and all systems' values for the key. + """ + customkey = client.system.custominfo.deleteKey(keyLabel) + return customkey + + +def smlm_list_keys(key, client): + """ + List the custom information keys defined for the user’s organization. + """ + customkeys = client.system.custominfo.listAllKeys(key) + return customkeys + + +def smlm_update_key(key, client, keyLabel, keyDescription): + """ + Update description of a custom key + """ + customkey = client.system.custominfo.updateKey(key, keyLabel, keyDescription) + return customkey + + +def main(): + """ + Main function that parses the command-line arguments and initiate the API calls. + """ + # Define how we want to process command line arguments + parser = argparse.ArgumentParser(prog='smlm_user',description='Manages SMLM custom keys') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-a','--add', action='store_true', help='Add custom key') + group.add_argument('-d','--delete', action='store_true', help='Delete custom key') + group.add_argument('-l','--list', action='store_true', help='List all custom keys') + group.add_argument('-t','--update', action='store_true', help='Update a custom key') + parser.add_argument('-u', '--user', type=str, required=True, help='User name with privileges to create other users') + parser.add_argument('-p', '--pwd', type=str, required=True, help='Password for user') + parser.add_argument('-s', '--server', type=str, required=True, help='Server FQDN') + parser.add_argument('--key', type=str, help='Custome key label.') + parser.add_argument('--description', type=str, help="Custom key description (optional).") + parser.add_argument('--debug', action='store_true', help="Use it to enable debug messages.") + inputparam=parser.parse_args() + + context = ssl._create_unverified_context() + client = ServerProxy('https://' + inputparam.server + '/rpc/api', context=context) + + key, client = smlm_login(inputparam.server, inputparam.user, inputparam.pwd) + + if(inputparam.add): + if( not inputparam.key): + sys.exit("Missing parameters, --key is required") + print("Adding key " + str(inputparam.key)) + smlm_create_key(key, client, inputparam.key, inputparam.description) + elif(inputparam.delete): + print("Deleting key " + str(inputparam.key)) + smlm_delete_key(key, client, inputparam.key) + elif(inputparam.list): + print("Retrieving the list of custom keys") + print(yaml.dump(smlm_list_keys(key, client))) + elif(inputparam.update): + print("Update custom key " + str(inputparam.key)) + smlm_update_key(key, client, inputparam.key, inputparam.description) + else: + print("Invalid or missing parameters") + if(inputparam.debug): + print(yaml.dump(inputparam)) + + smlm_logout(key, client) + + + +if __name__ == '__main__': + main() + diff --git a/scripts/smlm/manage_groups.py b/scripts/smlm/manage_groups.py new file mode 100644 index 0000000..057cabd --- /dev/null +++ b/scripts/smlm/manage_groups.py @@ -0,0 +1,174 @@ +#!/usr/bin/python3 +# +# Author/s: Raul Mahiques +# License: GPLv3 +# +# $Id$ +# + +from xmlrpc.client import ServerProxy +import ssl, argparse, yaml, sys + + + +def smlm_login(server, user, pwd): + """ + Performs an authentication login and returns the session key + """ + context = ssl._create_unverified_context() + client = ServerProxy('https://' + server + '/rpc/api', context=context) + key = client.auth.login(user, pwd) + return key, client + + +def smlm_logout(key, client): + """ + Performs a logout + """ + client.auth.logout(key) + + +def smlm_create_systemgroup(key, client, name, description=None): + """ + Create a new system group + """ + if(description == None): + description="Group "+name + + group = client.systemgroup.create(key, name, description) + return group + +def smlm_get_systemid(key, client, name): + """ + Get system IDs and last check in information for the given system name. + """ + system = client.system.getId(key, name) + return system + + +def smlm_addOrRemoveSystems(key, client, systemGroupName, servers, present): + """ + Add/remove the given servers to a system group. + """ + serverIds=[] + for server in servers.split(','): + results=smlm_get_systemid(key, client, server) +# print(yaml.dump(results)) +# print(results[0]) + serverIds.append(results[0]['id']) + client.systemgroup.addOrRemoveSystems(key, systemGroupName, serverIds, present) + + +def smlm_delete_systemgroup(key, client, systemGroupName): + """ + Delete a system group. + """ + group = client.systemgroup.delete(key, systemGroupName) + return group + + +def smlm_list_systemgroups(key, client): + """ + Retrieve a list of system groups that are accessible by the logged in user. + """ + groups = client.systemgroup.listAllGroups(key) + return groups + + +def smlm_list_systems(key, client): + """ + Returns a list of all servers visible to the user. + """ + systems = client.system.listSystems(key) + return systems + + +def smlm_listsystems_systemgroup(key, client, systemGroupName): + """ + Return a list of systems associated with this system group. User must have access to this system group. + """ + systems = client.systemgroup.listSystems(key, systemGroupName) + return systems + + +def smlm_is_system_in_group(key, client, system, group): + """ + Returns true or false depending if the system is in the group or not. + """ + systems = smlm_listsystems_systemgroup(key, client, group) + for i in systems: + if i['profile_name'] == system: + print("System "+system+" is present in group "+group) + break + + +def main(): + """ + Main function that parses the command-line arguments and initiate the API calls. + """ + # Define how we want to process command line arguments + parser = argparse.ArgumentParser(prog='smlm_user',description='Manages SMLM system groups') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-a','--add', action='store_true', help='Add system group') + group.add_argument('-d','--delete', action='store_true', help='Delete system group') + group.add_argument('-g','--getsystems', action='store_true', help='List systems in system group') + group.add_argument('-l','--list', action='store_true', help='List all system groups') + group.add_argument('-x','--listsystems', action='store_true', help='List all system') + group.add_argument('-b','--addsystem', action='store_true', help='Add a system/s to a group') + group.add_argument('-r','--delsystem', action='store_true', help='Remove a system/s from a group') + group.add_argument('-c','--check', action='store_true', help='Check if the system is in a group') + parser.add_argument('-u', '--user', type=str, required=True, help='User name with privileges to create other users') + parser.add_argument('-p', '--pwd', type=str, required=True, help='Password for user') + parser.add_argument('-s', '--server', type=str, required=True, help='Server FQDN') + parser.add_argument('--group', type=str, help='System group name.') + parser.add_argument('--system', type=str, help='System/s separated by ,.') + parser.add_argument('--description', type=str, help="Group description (optional).") + parser.add_argument('--debug', action='store_true', help="Use it to enable debug messages.") + inputparam=parser.parse_args() + + context = ssl._create_unverified_context() + client = ServerProxy('https://' + inputparam.server + '/rpc/api', context=context) + + key, client = smlm_login(inputparam.server, inputparam.user, inputparam.pwd) + + if(inputparam.add): + if( not inputparam.group): + sys.exit("Missing parameters, --group is required") + print("Adding group " + str(inputparam.group)) + smlm_create_systemgroup(key, client, inputparam.group, inputparam.description) + elif(inputparam.delete): + print("Deleting group " + str(inputparam.group)) + smlm_delete_systemgroup(key, client, inputparam.group) + elif(inputparam.getsystems): + print("Listing systems in group " + str(inputparam.group)) + print(yaml.dump(smlm_listsystems_systemgroup(key, client, inputparam.group))) + elif(inputparam.list): + print("Retrieving the list of system groups") + print(yaml.dump(smlm_list_systemgroups(key, client))) + elif(inputparam.listsystems): + print("Retrieving the list of systems") + print(yaml.dump(smlm_list_systems(key, client))) + elif(inputparam.addsystem): + print("Add system/s " + str(inputparam.system) + " to group " +str(inputparam.group) ) + smlm_addOrRemoveSystems(key, client, inputparam.group, inputparam.system, True) + elif(inputparam.delsystem): + print("Remove system/s " + str(inputparam.system) + " from group " +str(inputparam.group) ) + smlm_addOrRemoveSystems(key, client, inputparam.group, inputparam.system, False) + elif(inputparam.check): + print("Check if system "+ str(inputparam.system) + " is in group " +str(inputparam.group)) + smlm_is_system_in_group(key, client, inputparam.system, inputparam.group) + elif(inputparam.rm-system-to-group): + print("Deleting user " + str(inputparam.nusr)) + smlm_delete_user(key, client, inputparam.nusr) + else: + print("Invalid or missing parameters") + if(inputparam.debug): + print(yaml.dump(inputparam)) + + smlm_logout(key, client) + + + +if __name__ == '__main__': + main() + diff --git a/scripts/smlm/manage_org.py b/scripts/smlm/manage_org.py new file mode 100644 index 0000000..f679677 --- /dev/null +++ b/scripts/smlm/manage_org.py @@ -0,0 +1,122 @@ +#!/usr/bin/python3 +# +# Authors: Ricardo Mateus, Raul Mahiques +# +# $Id$ +# + +from xmlrpc.client import ServerProxy +import ssl, argparse, yaml + + + +def smlm_login(server, user, pwd): + """ + Performs an authentication login and returns the session key + """ + context = ssl._create_unverified_context() + client = ServerProxy('https://' + server + '/rpc/api', context=context) + key = client.auth.login(user, pwd) + return key, client + + +def smlm_logout(key, client): + """ + Performs a logout + """ + client.auth.logout(key) + + +def smlm_add_org(key, client, orgname, admusr, admpwd, admprefix, admfirstname, admlastname, admemail, admusepam): + """ + Creates an organization in SMLM with an admin user + """ + systems = client.org.create(key, orgname, admusr, admpwd, admprefix, admfirstname, admlastname, admemail, admusepam) + + +def smlm_get_org(key, client, orgname): + """ + Returns information about an organization in SMLM + """ + print(yaml.dump(lient.org.getDetails(key, orgname))) + + +def smlm_list_orgs(key, client): + """ + Returns the list of organization in SMLM + """ + return client.org.listOrgs(key) + + +def smlm_get_orgid(key, client, orgname): + """ + Retrieves information about a SMLM organization and returns the organization ID. + """ + orgDetails = client.org.getDetails(key, orgname) + return orgDetails['id'] + + +def smlm_del_org(key, client, orgid): + """ + Deletes an organization from SMLM + """ + print("Organization id to be delted: " + orgid) + result = client.org.delete(key, orgid) + print(result) + + +def main(): + """ + Main function that parses the command-line arguments and initiate the API calls. + """ + # Define how we want to process command line arguments + parser = argparse.ArgumentParser(prog='smlm_org',description='Manages SMLM Organizations') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-a','--add', action='store_true', help='Add Organization') + group.add_argument('-d','--delete', action='store_true', help='Delete Organization') + group.add_argument('-g','--get', action='store_true', help='Retrieve Organization information') + group.add_argument('-l','--list', action='store_true', help='List Organizations') + parser.add_argument('-u', '--user', type=str, required=True, help='User name with privileges to create organizations') + parser.add_argument('-p', '--pwd', type=str, required=True, help='Password for user') + parser.add_argument('-s', '--server', type=str, required=True, help='Server FQDN') + parser.add_argument('-o','--orgname', type=str, help='Organization name. Must meet same criteria as in the web UI.') + parser.add_argument('--admusr', type=str, help='New administrator login name.') + parser.add_argument('--admpwd', type=str, help='New administrator password.') + parser.add_argument('--admprefix', type=str, help="New administrator’s prefix. Must match one of the values available in the web UI. (i.e. Dr., Mr., Mrs., Sr., etc.)") + parser.add_argument('--admfirstname', type=str, help="New administrator’s first name.") + parser.add_argument('--admlastname', type=str, help="New administrator’s last name.") + parser.add_argument('--admemail', type=str, help="New administrator’s e-mail.") + parser.add_argument('--admusepam', action='store_true', help='True if PAM authentication should be used for the new administrator account.', dest="usepam" ) + parser.add_argument('--debug', action='store_true', help="Use it to enable debug messages.") + inputparam=parser.parse_args() + + context = ssl._create_unverified_context() + client = ServerProxy('https://' + inputparam.server + '/rpc/api', context=context) + + key, client = smlm_login(inputparam.server, inputparam.user, inputparam.pwd) + + if(inputparam.add and inputparam.orgname and inputparam.admusr and inputparam.admpwd and inputparam.admprefix and inputparam.admfirstname and inputparam.admlastname and inputparam.admemail): + print("Adding organization " + str(inputparam.orgname)) + smlm_add_org(key, client, inputparam.orgname, inputparam.admusr, inputparam.admpwd, inputparam.admprefix, inputparam.admfirstname, inputparam.admlastname, inputparam.admemail, inputparam.usepam or False) + elif(inputparam.delete): + print("Deleting organization " + str(inputparam.orgname)) + orgid=smlm_get_orgid(key, client, inputparam.orgname) + smlm_del_org(key, client, orgid) + elif(inputparam.get): + print("Retrieving information about organization: " + str(inputparam.orgname)) + print(str(smlm_get_org(key, client, inputparam.orgname))) + elif(inputparam.list): + print("Retrieving the list of organizations") + print(yaml.dump(smlm_list_orgs(key, client))) + else: + print("Invalid or missing parameters") + if(inputparam.debug): + print(yaml.dump(inputparam)) + + smlm_logout(key, client) + + + +if __name__ == '__main__': + main() + diff --git a/scripts/smlm/manage_systems.py b/scripts/smlm/manage_systems.py new file mode 100644 index 0000000..1fad9da --- /dev/null +++ b/scripts/smlm/manage_systems.py @@ -0,0 +1,216 @@ +#!/usr/bin/python3 +# +# Author/s: Raul Mahiques +# License: GPLv3 +# +# $Id$ +# + +from xmlrpc.client import ServerProxy +import ssl, argparse, yaml, sys, datetime + + +def smlm_login(server, user, pwd): + """ + Performs an authentication login and returns the session key + """ + context = ssl._create_unverified_context() + client = ServerProxy('https://' + server + '/rpc/api', context=context) + key = client.auth.login(user, pwd) + return key, client + + +def smlm_logout(key, client): + """ + Performs a logout + """ + client.auth.logout(key) + + +def smlm_add_customvalues(key, client, sid, customkey, value): + """ + Set custom values for the specified server. + """ + results = client.system.setCustomValues(key, sid, { customkey: value } ) + return results + +def smlm_get_systemid(key, client, name): + """ + Get system IDs and last check in information for the given system name. + """ + system = client.system.getId(key, name) + return system + + +def smlm_list_systems(key, client): + """ + Returns a list of all servers visible to the user. + """ + systems = client.system.listSystems(key) + return systems + + +def smlm_delete_system(key, client, sid): + """ + Delete a system given its server id synchronously without cleanup + """ + systems = client.system.deleteSystem(key, sid, cleanupType='FORCE_DELETE') + return systems + + +def smlm_schedule_applyHighstate(key, client, sid, when, test=False): + """ + Schedule highstate application for a given system. + """ + if not when: + earliest_occurrence = datetime.datetime.now(datetime.timezone.utc) + else: + earliest_occurrence = when + results = client.system.scheduleApplyHighstate(key, sid, earliest_occurrence, test ) + return results + +def smlm_schedule_packageRefresh(key, client, sid, when ): + """ + Schedule a package list refresh for a system. + """ + if not when: + earliest_occurrence = datetime.datetime.now(datetime.timezone.utc) + else: + earliest_occurrence = when + results = client.system.schedulePackageRefresh(key, sid, earliest_occurrence ) + return results + +def smam_system_getDetails(key, client, sid): + """ + Get system details. + """ + results = client.system.getDetails(key, sid) + return results + + +def smlm_schedule_HardwareRefresh(key, client, sid, when): + """ + Schedule a hardware refresh for a system. + """ + if not when: + earliest_occurrence = datetime.datetime.now(datetime.timezone.utc) + else: + earliest_occurrence = when + results = client.system.scheduleHardwareRefresh(key, sid, earliest_occurrence ) + return results + + +def smlm_schedule_state(key, client, sid, state, when, test=False): + """ + Schedule a state/s for a system. + """ + if not when: + earliest_occurrence = datetime.datetime.now(datetime.timezone.utc) + else: + earliest_occurrence = when + states=[] + if not state: + states=['certs','channels','packages','services.salt-minion'] + else: + for i in state.split(','): + states.append(i) + + results = client.system.scheduleApplyStates(key, sid, states, earliest_occurrence, test ) + return results + + + +def main(): + """ + Main function that parses the command-line arguments and initiate the API calls. + """ + # Define how we want to process command line arguments + parser = argparse.ArgumentParser(prog='smlm_user',description='Manages SMLM system groups') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--addcustomvalue', action='store_true', help='Add custom value to a system') + group.add_argument('-d','--delete', action='store_true', help='Delete system') + group.add_argument('-l','--list', action='store_true', help='List all system groups') + group.add_argument('--scheduleapplyhighstate', action='store_true', help='Schedule highstate application for a given system.') + group.add_argument('--schedulepackagerefresh', action='store_true', help='Schedule a package list refresh for a system.') + group.add_argument('--schedulehardwarerefresh', action='store_true', help='Schedule a hardware refresh for a system.') + group.add_argument('--schedulestate', action='store_true', help='Schedule a state refresh for a system.') + group.add_argument('-g','--getinfo', action='store_true', help='Get system info') + parser.add_argument('-u', '--user', type=str, required=True, help='User name with privileges to create other users') + parser.add_argument('-p', '--pwd', type=str, required=True, help='Password for user') + parser.add_argument('-s', '--server', type=str, required=True, help='Server FQDN') + parser.add_argument('--customkey', type=str, help='Custom key name.') + parser.add_argument('--system', type=str, help='System name.') + parser.add_argument('--keyvalue', type=str, help="Custom key value.") + parser.add_argument('--executiondate', type=str, help="Date for the action to be executed, default is now, format: " + str(datetime.datetime.now(datetime.timezone.utc)) +".") + parser.add_argument('--state', type=str, help='state/s serparated by , .') + parser.add_argument('--debug', action='store_true', help="Use it to enable debug messages.") + inputparam=parser.parse_args() + + context = ssl._create_unverified_context() + client = ServerProxy('https://' + inputparam.server + '/rpc/api', context=context) + + key, client = smlm_login(inputparam.server, inputparam.user, inputparam.pwd) + + + if(inputparam.addcustomvalue): + if( not inputparam.customkey or not inputparam.keyvalue or not inputparam.system): + sys.exit("Missing parameters, --customkey, --system, --keyvalue are required") + print("Adding custom key \"" + str(inputparam.customkey) + "\" with value: \"" + str(inputparam.keyvalue) + "\" to system "+ str(inputparam.system)) + results=smlm_get_systemid(key, client, inputparam.system) + smlm_add_customvalues(key, client, results[0]['id'], inputparam.customkey, inputparam.keyvalue) + elif(inputparam.delete): + if( not inputparam.system): + sys.exit("Missing parameters, --system is required") + print("Deleting system " + str(inputparam.system)) + results=smlm_get_systemid(key, client, inputparam.system) + sid=results[0]['id'] + smlm_delete_system(key, client, sid) + elif(inputparam.list): + print("Retrieving the list of systems") + print(yaml.dump(smlm_list_systems(key, client))) + elif(inputparam.scheduleapplyhighstate): + if( not inputparam.system): + sys.exit("Missing parameters, --system is required") + print("Scheduling apply highstate for system " + str(inputparam.system)) + systemid=smlm_get_systemid(key, client, inputparam.system) + results=smlm_schedule_applyHighstate(key, client, systemid[0]['id'], inputparam.executiondate, test=False) + elif(inputparam.schedulepackagerefresh): + if( not inputparam.system): + sys.exit("Missing parameters, --system is required") + print("Scheduleing a package refresh for system " + str(inputparam.system)) + systemid=smlm_get_systemid(key, client, inputparam.system) + results=smlm_schedule_packageRefresh(key, client, systemid[0]['id'], inputparam.executiondate) + + elif(inputparam.schedulehardwarerefresh): + if( not inputparam.system): + sys.exit("Missing parameters, --system is required") + print("Scheduleing a hardware refresh for system " + str(inputparam.system)) + systemid=smlm_get_systemid(key, client, inputparam.system) + results=smlm_schedule_HardwareRefresh(key, client, systemid[0]['id'], inputparam.executiondate) + + elif(inputparam.schedulestate): + if( not inputparam.system): + sys.exit("Missing parameters, --system is required") + print("Scheduleing a state " + str(inputparam.state) + " refresh for system " + str(inputparam.system)) + systemid=smlm_get_systemid(key, client, inputparam.system) + + results=smlm_schedule_state(key, client, systemid[0]['id'], inputparam.state, inputparam.executiondate, test=False) + + elif(inputparam.getinfo): + if( not inputparam.system): + sys.exit("Missing parameters, --system is required") + print("Get information about system " + str(inputparam.system)) + systemid=smlm_get_systemid(key, client, inputparam.system) + print(yaml.dump(smam_system_getDetails(key, client, systemid[0]['id']))) + else: + print("Invalid or missing parameters") + if(inputparam.debug): + print(yaml.dump(inputparam)) + + smlm_logout(key, client) + + + +if __name__ == '__main__': + main() + diff --git a/scripts/smlm/manage_users.py b/scripts/smlm/manage_users.py new file mode 100644 index 0000000..5f4be94 --- /dev/null +++ b/scripts/smlm/manage_users.py @@ -0,0 +1,168 @@ +#!/usr/bin/python3 +# +# Author/s: Raul Mahiques +# License: GPLv3 +# +# $Id$ +# + +from xmlrpc.client import ServerProxy +import ssl, argparse, yaml, sys + + + +def smlm_login(server, user, pwd): + """ + Performs an authentication login and returns the session key + """ + context = ssl._create_unverified_context() + client = ServerProxy('https://' + server + '/rpc/api', context=context) + key = client.auth.login(user, pwd) + return key, client + + +def smlm_logout(key, client): + """ + Performs a logout + """ + client.auth.logout(key) + + +def smlm_create_user(key, client, login, password, firstName=None, lastName=None, email=None): + """ + Creates a user + """ + if(firstName == None): + firstName=login + if(lastName == None): + lastName=login + if(email == None): + email=login+"@"+login+"."+login + + users = client.user.create(key, login, password, firstName, lastName, email) + return users + +def smlm_addRole_user(key, client, login, roles): + """ + Adds a role to the user + """ + for role in roles.split(','): + client.user.addRole(key, login, role) + + +def smlm_delete_user(key, client, login): + """ + Delete a user + """ + users = client.user.delete(key, login) + return users + + +def smlm_disable_user(key, client, login): + """ + Disable user + """ + users = client.user.disable(key, login) + return users + + +def smlm_enable_user(key, client, login): + """ + Enable user + """ + users = client.user.enable(key, login) + return users + + +def smlm_setErrataNotifications_user(key, client, login, value=False): + """ + Enables/disables errata mail notifications for a specific user. + """ + users = client.user.setErrataNotifications(key, login, value) + return users + + +def smlm_setReadOnly_user(key, client, login, readOnly=True): + """ + Sets whether the target user should have only read-only API access or standard full scale access. + """ + users = client.user.setReadOnly(key, login, readOnly) + return users + + +def smlm_listAssignableRoles(key, client): + """ + Returns a list of user roles that this user can assign to others. + """ + roles = client.user.listAssignableRoles(key) + return roles + + +def smlm_listUsers(key, client): + """ + Returns a list of users. + """ + return client.user.listUsers(key) + + +def main(): + """ + Main function that parses the command-line arguments and initiate the API calls. + """ + # Define how we want to process command line arguments + parser = argparse.ArgumentParser(prog='smlm_user',description='Manages SMLM Users') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-a','--add', action='store_true', help='Add User') + group.add_argument('-d','--delete', action='store_true', help='Delete User') + group.add_argument('-g','--get', action='store_true', help='Retrieve User information') + group.add_argument('-l','--list', action='store_true', help='List Users and Assignable Roles') + parser.add_argument('-u', '--user', type=str, required=True, help='User name with privileges to create other users') + parser.add_argument('-p', '--pwd', type=str, required=True, help='Password for user') + parser.add_argument('-s', '--server', type=str, required=True, help='Server FQDN') + parser.add_argument('--nusr', type=str, help='New user login name.') + parser.add_argument('--npwd', type=str, help='New user password.') + parser.add_argument('--nfirstname', type=str, help="New user first name.") + parser.add_argument('--nlastname', type=str, help="New user last name.") + parser.add_argument('--nemail', type=str, help="New user e-mail.") + parser.add_argument('--nrole', type=str, help='New user role' ) + parser.add_argument('--debug', action='store_true', help="Use it to enable debug messages.") + inputparam=parser.parse_args() + + context = ssl._create_unverified_context() + client = ServerProxy('https://' + inputparam.server + '/rpc/api', context=context) + + key, client = smlm_login(inputparam.server, inputparam.user, inputparam.pwd) + + if(inputparam.add): + if( not inputparam.nrole or not inputparam.npwd or not inputparam.nusr): + sys.exit("Missing parameters, --nusr --npwd and --nrole are required") + + print("Adding user " + str(inputparam.nusr)) + smlm_create_user(key, client, inputparam.nusr, inputparam.npwd, inputparam.nfirstname or None, inputparam.nlastname or None, inputparam.nemail or None ) + smlm_addRole_user(key, client, inputparam.nusr, inputparam.nrole) + smlm_enable_user(key, client, inputparam.nusr) + smlm_setErrataNotifications_user(key, client, inputparam.nusr) + + elif(inputparam.delete): + print("Deleting user " + str(inputparam.nusr)) + smlm_delete_user(key, client, inputparam.nusr) + elif(inputparam.get): + print("Not implemented yet") + elif(inputparam.list): + print("Retrieving the list of users and assignable roles") + print("Assignable Roles:") + print(yaml.dump(smlm_listAssignableRoles(key, client))) + print("Existing Users:") + print(yaml.dump(smlm_listUsers(key, client))) + else: + print("Invalid or missing parameters") + if(inputparam.debug): + print(yaml.dump(inputparam)) + + smlm_logout(key, client) + + + +if __name__ == '__main__': + main() + diff --git a/web/css/instruqt.css b/web/css/instruqt.css new file mode 100644 index 0000000..9bd7311 --- /dev/null +++ b/web/css/instruqt.css @@ -0,0 +1,71 @@ +* { + font-family: suse; + src: url('https://fonts.google.com/specimen/SUSE'); +} +.hovereffect { + border-radius: 25px 25px 25px 25px; + background: linear-gradient(#30ba78 0 0) var(--hundredpercent, 0) / var(--hundredpercent, 0) no-repeat; + transition: 0.5s, background-position 0s; + padding: 5px; +} +.hovereffect:hover { + --hundredpercent: 100%; + color: white; + border-radius: 10px 25px 10px 25px; +} +.smlmext { + color: #fe7c3f; +} +.smlm { + color: #fe7c3f; +} +.suse { + color: #30ba78; +} +.smls { + color: #2453ff; +} +.smlsext { + color: #2453ff; +} +.companyname { + color: #008657; +} +.liberty { + color: #efefef; +} +.sles { + color: #90ebcd; +} + +.bottoms { + vertical-align: middle; + height: 50%; + width: 50%; + margin: 0px; + padding: 0px; + object-fit: contain; +} + +img.animatedgif { + --borderthickness: 5pt; + --colors: #0000 25%,#30ba78 0; + padding: 10px; + background: + conic-gradient(from 90deg at top var(--borderthickness) left var(--borderthickness),var(--colors)) 0 0, + conic-gradient(from 180deg at top var(--borderthickness) right var(--borderthickness),var(--colors)) 100% 0, + conic-gradient(from 0deg at bottom var(--borderthickness) left var(--borderthickness),var(--colors)) 0 100%, + conic-gradient(from -90deg at bottom var(--borderthickness) right var(--borderthickness),var(--colors)) 100% 100%; + background-size: 50px 50px; + background-repeat: no-repeat; + transition: 1s; +} + +img.animatedgif:hover { + background-size: 51% 51%; +} + +img.logos { + border-radius: 10px; +} +