Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/agents/openstack/fence_openstack.py b/agents/openstack/fence_openstack.py
index e7aea086..56f6fee7 100644
--- a/agents/openstack/fence_openstack.py
+++ b/agents/openstack/fence_openstack.py
@@ -1,381 +1,410 @@
-#!@PYTHON@ -tt
+#!/usr/libexec/platform-python -tt
import atexit
import logging
import sys
import os
import urllib3
-sys.path.append("@FENCEAGENTSLIBDIR@")
+sys.path.append("/usr/share/fence")
from fencing import *
from fencing import fail_usage, run_delay, source_env
try:
from novaclient import client
from novaclient.exceptions import Conflict, NotFound
except ImportError:
pass
urllib3.disable_warnings(urllib3.exceptions.SecurityWarning)
def translate_status(instance_status):
if instance_status == "ACTIVE":
return "on"
elif instance_status == "SHUTOFF":
return "off"
return "unknown"
def get_cloud(options):
import yaml
clouds_yaml = "~/.config/openstack/clouds.yaml"
if not os.path.exists(os.path.expanduser(clouds_yaml)):
clouds_yaml = "/etc/openstack/clouds.yaml"
if not os.path.exists(os.path.expanduser(clouds_yaml)):
fail_usage("Failed: ~/.config/openstack/clouds.yaml and /etc/openstack/clouds.yaml does not exist")
clouds_yaml = os.path.expanduser(clouds_yaml)
if os.path.exists(clouds_yaml):
with open(clouds_yaml, "r") as yaml_stream:
try:
clouds = yaml.safe_load(yaml_stream)
except yaml.YAMLError as exc:
fail_usage("Failed: Unable to read: " + clouds_yaml)
cloud = clouds.get("clouds").get(options["--cloud"])
if not cloud:
fail_usage("Cloud: {} not found.".format(options["--cloud"]))
return cloud
def get_nodes_list(conn, options):
logging.info("Running %s action", options["--action"])
result = {}
response = conn.servers.list(detailed=True)
if response is not None:
for item in response:
instance_id = item.id
instance_name = item.name
instance_status = item.status
result[instance_id] = (instance_name, translate_status(instance_status))
return result
def get_power_status(conn, options):
logging.info("Running %s action on %s", options["--action"], options["--plug"])
server = None
try:
server = conn.servers.get(options["--plug"])
except NotFound as e:
fail_usage("Failed: Not Found: " + str(e))
if server is None:
fail_usage("Server %s not found", options["--plug"])
state = server.status
status = translate_status(state)
logging.info("get_power_status: %s (state: %s)" % (status, state))
return status
def set_power_status(conn, options):
logging.info("Running %s action on %s", options["--action"], options["--plug"])
action = options["--action"]
server = None
try:
server = conn.servers.get(options["--plug"])
except NotFound as e:
fail_usage("Failed: Not Found: " + str(e))
if server is None:
fail_usage("Server %s not found", options["--plug"])
if action == "on":
logging.info("Starting instance " + server.name)
try:
server.start()
except Conflict as e:
fail_usage(e)
logging.info("Called start API call for " + server.id)
if action == "off":
logging.info("Stopping instance " + server.name)
try:
server.stop()
except Conflict as e:
fail_usage(e)
logging.info("Called stop API call for " + server.id)
if action == "reboot":
logging.info("Rebooting instance " + server.name)
try:
server.reboot("HARD")
except Conflict as e:
fail_usage(e)
logging.info("Called reboot hard API call for " + server.id)
def nova_login(username, password, projectname, auth_url, user_domain_name,
- project_domain_name, ssl_insecure, cacert, apitimeout):
+ project_domain_name, ssl_insecure, cacert, apitimeout, auth_plugin):
legacy_import = False
try:
from keystoneauth1 import loading
from keystoneauth1 import session as ksc_session
from keystoneauth1.exceptions.discovery import DiscoveryFailure
from keystoneauth1.exceptions.http import Unauthorized
except ImportError:
try:
from keystoneclient import session as ksc_session
from keystoneclient.auth.identity import v3
legacy_import = True
except ImportError:
fail_usage("Failed: Keystone client not found or not accessible")
+ if auth_plugin == "v3applicationcredential":
+ loader = loading.get_plugin_loader("v3applicationcredential")
+ auth = loader.load_from_options(
+ auth_url=auth_url,
+ application_credential_id=username,
+ application_credential_secret=password,
+ )
- if not legacy_import:
+ elif not legacy_import:
loader = loading.get_plugin_loader("password")
auth = loader.load_from_options(
auth_url=auth_url,
username=username,
password=password,
project_name=projectname,
user_domain_name=user_domain_name,
project_domain_name=project_domain_name,
)
else:
auth = v3.Password(
auth_url=auth_url,
username=username,
password=password,
project_name=projectname,
user_domain_name=user_domain_name,
project_domain_name=project_domain_name,
cacert=cacert,
)
caverify=True
if ssl_insecure:
caverify=False
elif cacert:
caverify=cacert
session = ksc_session.Session(auth=auth, verify=caverify, timeout=apitimeout)
nova = client.Client("2", session=session, timeout=apitimeout)
apiversion = None
try:
apiversion = nova.versions.get_current()
except DiscoveryFailure as e:
fail_usage("Failed: Discovery Failure: " + str(e))
except Unauthorized as e:
fail_usage("Failed: Unauthorized: " + str(e))
except Exception as e:
logging.error(e)
logging.debug("Nova version: %s", apiversion)
return nova
def define_new_opts():
all_opt["auth-url"] = {
"getopt": ":",
"longopt": "auth-url",
"help": "--auth-url=[authurl] Keystone Auth URL",
"required": "0",
"shortdesc": "Keystone Auth URL",
"order": 2,
}
all_opt["project-name"] = {
"getopt": ":",
"longopt": "project-name",
"help": "--project-name=[project] Tenant Or Project Name",
"required": "0",
"shortdesc": "Keystone Project",
"default": "admin",
"order": 3,
}
all_opt["user-domain-name"] = {
"getopt": ":",
"longopt": "user-domain-name",
"help": "--user-domain-name=[domain] Keystone User Domain Name",
"required": "0",
"shortdesc": "Keystone User Domain Name",
"default": "Default",
"order": 4,
}
all_opt["project-domain-name"] = {
"getopt": ":",
"longopt": "project-domain-name",
"help": "--project-domain-name=[domain] Keystone Project Domain Name",
"required": "0",
"shortdesc": "Keystone Project Domain Name",
"default": "Default",
"order": 5,
}
all_opt["cloud"] = {
"getopt": ":",
"longopt": "cloud",
"help": "--cloud=[cloud] Openstack cloud (from ~/.config/openstack/clouds.yaml or /etc/openstack/clouds.yaml).",
"required": "0",
"shortdesc": "Cloud from clouds.yaml",
"order": 6,
}
all_opt["openrc"] = {
"getopt": ":",
"longopt": "openrc",
"help": "--openrc=[openrc] Path to the openrc config file",
"required": "0",
"shortdesc": "openrc config file",
"order": 7,
}
all_opt["uuid"] = {
"getopt": ":",
"longopt": "uuid",
"help": "--uuid=[uuid] Replaced by -n, --plug",
"required": "0",
"shortdesc": "Replaced by port/-n/--plug",
"order": 8,
}
all_opt["cacert"] = {
"getopt": ":",
"longopt": "cacert",
"help": "--cacert=[cacert] Path to the PEM file with trusted authority certificates (override global CA trust)",
"required": "0",
"shortdesc": "SSL X.509 certificates file",
"default": "",
"order": 9,
}
all_opt["apitimeout"] = {
"getopt": ":",
"type": "second",
"longopt": "apitimeout",
"help": "--apitimeout=[seconds] Timeout to use for API calls",
"shortdesc": "Timeout in seconds to use for API calls, default is 60.",
"required": "0",
"default": 60,
"order": 10,
}
+ all_opt["auth_plugin"] = {
+ "getopt": ":",
+ "longopt": "auth_plugin",
+ "help": "--auth_plugin=[PLUGIN] Plugin name to use (default password)",
+ "required": "0",
+ "default": "password",
+ "shortdesc": "Specify what auth plugin to use. One from v2password, v3applicationcredential, v3totp, v3oidcpassword, v3oauth2clientcredential, token, v3oidcauthcode, v3multifactor, v3tokenlessauth, v3oidcclientcredentials, v3oidcaccesstoken, v3password, v3token, password, admin_token, http_basic, noauth, v2token",
+ "order": 11,
+ }
def main():
conn = None
device_opt = [
"login",
"no_login",
"passwd",
"no_password",
"auth-url",
"project-name",
"user-domain-name",
"project-domain-name",
"cloud",
"openrc",
"port",
"no_port",
"uuid",
"ssl_insecure",
"cacert",
"apitimeout",
+ "auth_plugin",
]
atexit.register(atexit_handler)
define_new_opts()
all_opt["port"]["required"] = "0"
all_opt["port"]["help"] = "-n, --plug=[UUID] UUID of the node to be fenced"
all_opt["port"]["shortdesc"] = "UUID of the node to be fenced."
all_opt["power_timeout"]["default"] = "60"
options = check_input(device_opt, process_input(device_opt))
# workaround to avoid regressions
if "--uuid" in options:
options["--plug"] = options["--uuid"]
del options["--uuid"]
elif ("--help" not in options
and options["--action"] in ["off", "on", "reboot", "status", "validate-all"]
and "--plug" not in options):
stop_after_error = False if options["--action"] == "validate-all" else True
fail_usage(
"Failed: You have to enter plug number or machine identification",
stop_after_error,
)
docs = {}
docs["shortdesc"] = "Fence agent for OpenStack's Nova service"
docs["longdesc"] = "fence_openstack is a Power Fencing agent \
which can be used with machines controlled by the Openstack's Nova service. \
This agent calls the python-novaclient and it is mandatory to be installed "
docs["vendorurl"] = "https://wiki.openstack.org/wiki/Nova"
show_docs(options, docs)
run_delay(options)
+ auth_plugin = options["--auth_plugin"]
+ projectname = None
+ user_domain_name = None
+ project_domain_name = None
+
if options.get("--cloud"):
cloud = get_cloud(options)
- username = cloud.get("auth").get("username")
- password = cloud.get("auth").get("password")
- projectname = cloud.get("auth").get("project_name")
+ if auth_plugin == "v3applicationcredential":
+ username = cloud.get("auth").get("application_credential_id")
+ password = cloud.get("auth").get("application_credential_secret")
+ else:
+ username = cloud.get("auth").get("username")
+ password = cloud.get("auth").get("password")
+ projectname = cloud.get("auth").get("project_name")
+ user_domain_name = cloud.get("auth").get("user_domain_name")
+ project_domain_name = cloud.get("auth").get("project_domain_name")
auth_url = None
+
try:
auth_url = cloud.get("auth").get("auth_url")
except KeyError:
fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
- user_domain_name = cloud.get("auth").get("user_domain_name")
- project_domain_name = cloud.get("auth").get("project_domain_name")
+
caverify = cloud.get("verify")
if caverify in [True, False]:
options["--ssl-insecure"] = caverify
else:
options["--cacert"] = caverify
elif options.get("--openrc"):
if not os.path.exists(os.path.expanduser(options["--openrc"])):
fail_usage("Failed: {} does not exist".format(options.get("--openrc")))
source_env(options["--openrc"])
env = os.environ
username = env.get("OS_USERNAME")
password = env.get("OS_PASSWORD")
projectname = env.get("OS_PROJECT_NAME")
auth_url = None
try:
auth_url = env["OS_AUTH_URL"]
except KeyError:
fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
user_domain_name = env.get("OS_USER_DOMAIN_NAME")
project_domain_name = env.get("OS_PROJECT_DOMAIN_NAME")
else:
username = options["--username"]
password = options["--password"]
projectname = options["--project-name"]
auth_url = None
try:
auth_url = options["--auth-url"]
except KeyError:
fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
user_domain_name = options["--user-domain-name"]
project_domain_name = options["--project-domain-name"]
ssl_insecure = "--ssl-insecure" in options
cacert = options["--cacert"]
apitimeout = options["--apitimeout"]
try:
conn = nova_login(
username,
password,
projectname,
auth_url,
user_domain_name,
project_domain_name,
ssl_insecure,
cacert,
apitimeout,
+ auth_plugin,
)
except Exception as e:
fail_usage("Failed: Unable to connect to Nova: " + str(e))
# Operate the fencing device
result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list)
sys.exit(result)
if __name__ == "__main__":
main()

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 5:59 AM (15 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018274
Default Alt Text
(14 KB)

Event Timeline