Solutions API changes
Signed-off-by: plumgrid <Junaid Ali>
This commit is contained in:
parent
420e95c089
commit
3cd01f1099
8
actions.yaml
Normal file
8
actions.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
restart-pg:
|
||||||
|
description: Restart the plumgrid-director unit's service.
|
||||||
|
post-ips:
|
||||||
|
description: Post PLUMgrid nodes IPs to Solutions API server.
|
||||||
|
post-zone-info:
|
||||||
|
description: Post Zone info to Solutions API server.
|
||||||
|
post-license:
|
||||||
|
description: Post PLUMgrid License to Solutions API server.
|
65
actions/actions.py
Executable file
65
actions/actions.py
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('hooks/')
|
||||||
|
|
||||||
|
from charmhelpers.core.hookenv import action_fail
|
||||||
|
from pg_dir_utils import (
|
||||||
|
restart_pg,
|
||||||
|
sapi_post_zone_info,
|
||||||
|
sapi_post_license,
|
||||||
|
sapi_post_ips
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def restart_pg(args):
|
||||||
|
"""
|
||||||
|
Restart PLUMgrid services.
|
||||||
|
"""
|
||||||
|
restart_pg()
|
||||||
|
|
||||||
|
|
||||||
|
def post_ips(args):
|
||||||
|
"""
|
||||||
|
POST plumgrid nodes IPs to solutions api server.
|
||||||
|
"""
|
||||||
|
sapi_post_ips()
|
||||||
|
|
||||||
|
|
||||||
|
def post_zone_info(args):
|
||||||
|
"""
|
||||||
|
POST zone information to solutions api server
|
||||||
|
"""
|
||||||
|
sapi_post_zone_info()
|
||||||
|
|
||||||
|
|
||||||
|
def post_license(args):
|
||||||
|
"""
|
||||||
|
POST PLUMgrid License to solutions api server
|
||||||
|
"""
|
||||||
|
sapi_post_license()
|
||||||
|
|
||||||
|
|
||||||
|
# A dictionary of all the defined actions to callables (which take
|
||||||
|
# parsed arguments).
|
||||||
|
ACTIONS = {"restart-pg": restart_pg, "post-ips": post_ips, "post-zone-info": post_zone_info,
|
||||||
|
"post-license": post_license}
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
action_name = os.path.basename(args[0])
|
||||||
|
try:
|
||||||
|
action = ACTIONS[action_name]
|
||||||
|
except KeyError:
|
||||||
|
return "Action %s undefined" % action_name
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
action(args)
|
||||||
|
except Exception as e:
|
||||||
|
action_fail(str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main(sys.argv))
|
1
actions/post-ips
Symbolic link
1
actions/post-ips
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
actions.py
|
1
actions/post-license
Symbolic link
1
actions/post-license
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
actions.py
|
1
actions/post-zone-info
Symbolic link
1
actions/post-zone-info
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
actions.py
|
1
actions/restart-pg
Symbolic link
1
actions/restart-pg
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
actions.py
|
11
config.yaml
11
config.yaml
@ -56,3 +56,14 @@ options:
|
|||||||
default: 127.0.0.1
|
default: 127.0.0.1
|
||||||
type: string
|
type: string
|
||||||
description: IP address of the PLUMgrid Operations VM Management interface.
|
description: IP address of the PLUMgrid Operations VM Management interface.
|
||||||
|
lcm-ip:
|
||||||
|
type: string
|
||||||
|
description: IP used by Solutions API to get/post cloud information.
|
||||||
|
sapi-port:
|
||||||
|
default: 8099
|
||||||
|
type: int
|
||||||
|
description: Port used by Solutions API to get/post cloud information.
|
||||||
|
sapi-zone:
|
||||||
|
default: pgzone
|
||||||
|
type: string
|
||||||
|
description: Zone name used by Solutions API to get/post cloud information.
|
||||||
|
@ -26,6 +26,30 @@ from socket import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _pg_edge_ips():
|
||||||
|
'''
|
||||||
|
Inspects edge-peer relation and returns the
|
||||||
|
ips of the edge nodes
|
||||||
|
'''
|
||||||
|
return [get_host_ip(rdata['private-address'])
|
||||||
|
for rid in relation_ids("plumgrid")
|
||||||
|
for rdata in
|
||||||
|
(relation_get(rid=rid, unit=unit) for unit in related_units(rid))
|
||||||
|
if 'edge-peer' in rdata]
|
||||||
|
|
||||||
|
|
||||||
|
def _pg_gateway_ips():
|
||||||
|
'''
|
||||||
|
Inspects gateway-peer relation and returns the
|
||||||
|
ips of the gateway nodes
|
||||||
|
'''
|
||||||
|
return [get_host_ip(rdata['private-address'])
|
||||||
|
for rid in relation_ids("plumgrid")
|
||||||
|
for rdata in
|
||||||
|
(relation_get(rid=rid, unit=unit) for unit in related_units(rid))
|
||||||
|
if 'gateway-peer' in rdata]
|
||||||
|
|
||||||
|
|
||||||
def _pg_dir_ips():
|
def _pg_dir_ips():
|
||||||
'''
|
'''
|
||||||
Inspects plumgrid-director peer relation and returns the
|
Inspects plumgrid-director peer relation and returns the
|
||||||
|
@ -9,7 +9,6 @@ import sys
|
|||||||
import time
|
import time
|
||||||
from charmhelpers.core.host import service_running
|
from charmhelpers.core.host import service_running
|
||||||
from charmhelpers.contrib.network.ip import is_ip
|
from charmhelpers.contrib.network.ip import is_ip
|
||||||
|
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
Hooks,
|
Hooks,
|
||||||
UnregisteredHookError,
|
UnregisteredHookError,
|
||||||
@ -42,7 +41,10 @@ from pg_dir_utils import (
|
|||||||
restart_on_change,
|
restart_on_change,
|
||||||
director_cluster_ready,
|
director_cluster_ready,
|
||||||
configure_pg_sources,
|
configure_pg_sources,
|
||||||
configure_analyst_opsvm
|
configure_analyst_opsvm,
|
||||||
|
sapi_post_ips,
|
||||||
|
sapi_post_license,
|
||||||
|
sapi_post_zone_info
|
||||||
)
|
)
|
||||||
|
|
||||||
hooks = Hooks()
|
hooks = Hooks()
|
||||||
@ -67,6 +69,7 @@ def install():
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('director-relation-joined')
|
@hooks.hook('director-relation-joined')
|
||||||
|
@hooks.hook('director-relation-changed')
|
||||||
@restart_on_change(restart_map())
|
@restart_on_change(restart_map())
|
||||||
def dir_joined():
|
def dir_joined():
|
||||||
'''
|
'''
|
||||||
@ -77,16 +80,24 @@ def dir_joined():
|
|||||||
CONFIGS.write_all()
|
CONFIGS.write_all()
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('plumgrid-relation-joined')
|
@hooks.hook('plumgrid-relation-joined',
|
||||||
|
'plumgrid-relation-changed',
|
||||||
|
'plumgrid-relation-departed')
|
||||||
def plumgrid_joined(relation_id=None):
|
def plumgrid_joined(relation_id=None):
|
||||||
'''
|
'''
|
||||||
This hook is run when relation with edge or gateway is created.
|
This hook is run when relation with edge or gateway is created.
|
||||||
'''
|
'''
|
||||||
opsvm_ip = config('opsvm-ip')
|
opsvm_ip = config('opsvm-ip')
|
||||||
if not is_ip(opsvm_ip):
|
if not is_ip(opsvm_ip):
|
||||||
raise ValueError('Incorrect OPSVM IP specified')
|
raise ValueError('Invalid OPSVM IP specified!')
|
||||||
else:
|
else:
|
||||||
relation_set(relation_id=relation_id, opsvm_ip=opsvm_ip)
|
relation_set(relation_id=relation_id, opsvm_ip=opsvm_ip)
|
||||||
|
if is_leader():
|
||||||
|
if is_ip(config('lcm-ip')):
|
||||||
|
sapi_post_ips()
|
||||||
|
sapi_post_zone_info()
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid LCM IP specified!')
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('plumgrid-configs-relation-joined')
|
@hooks.hook('plumgrid-configs-relation-joined')
|
||||||
@ -117,6 +128,8 @@ def config_changed():
|
|||||||
if charm_config.changed('plumgrid-license-key'):
|
if charm_config.changed('plumgrid-license-key'):
|
||||||
if is_leader() and post_pg_license():
|
if is_leader() and post_pg_license():
|
||||||
log("PLUMgrid License Posted")
|
log("PLUMgrid License Posted")
|
||||||
|
# Post PG license to Sol-API
|
||||||
|
sapi_post_license()
|
||||||
if charm_config.changed('fabric-interfaces'):
|
if charm_config.changed('fabric-interfaces'):
|
||||||
if not fabric_interface_changed():
|
if not fabric_interface_changed():
|
||||||
log("Fabric interface already set")
|
log("Fabric interface already set")
|
||||||
@ -124,6 +137,8 @@ def config_changed():
|
|||||||
stop_pg()
|
stop_pg()
|
||||||
if charm_config.changed('plumgrid-virtual-ip'):
|
if charm_config.changed('plumgrid-virtual-ip'):
|
||||||
CONFIGS.write_all()
|
CONFIGS.write_all()
|
||||||
|
for rid in relation_ids('plumgrid'):
|
||||||
|
plumgrid_joined(rid)
|
||||||
stop_pg()
|
stop_pg()
|
||||||
for rid in relation_ids('plumgrid-configs'):
|
for rid in relation_ids('plumgrid-configs'):
|
||||||
plumgrid_configs_joined(rid)
|
plumgrid_configs_joined(rid)
|
||||||
@ -149,6 +164,12 @@ def config_changed():
|
|||||||
for rid in relation_ids('plumgrid'):
|
for rid in relation_ids('plumgrid'):
|
||||||
plumgrid_joined(rid)
|
plumgrid_joined(rid)
|
||||||
stop_pg()
|
stop_pg()
|
||||||
|
# TODO
|
||||||
|
if (charm_config.changed('sapi-port') or
|
||||||
|
charm_config.changed('lcm-ip') or
|
||||||
|
charm_config.changed('sapi-zone')):
|
||||||
|
for rid in relation_ids('plumgrid'):
|
||||||
|
plumgrid_joined(rid)
|
||||||
ensure_mtu()
|
ensure_mtu()
|
||||||
CONFIGS.write_all()
|
CONFIGS.write_all()
|
||||||
if not service_running('plumgrid'):
|
if not service_running('plumgrid'):
|
||||||
@ -161,6 +182,7 @@ def start():
|
|||||||
This hook is run when the charm is started.
|
This hook is run when the charm is started.
|
||||||
'''
|
'''
|
||||||
configure_analyst_opsvm()
|
configure_analyst_opsvm()
|
||||||
|
sapi_post_zone_info()
|
||||||
if config('plumgrid-license-key') is not None:
|
if config('plumgrid-license-key') is not None:
|
||||||
count = 0
|
count = 0
|
||||||
while (count < 10):
|
while (count < 10):
|
||||||
|
@ -24,6 +24,8 @@ from charmhelpers.contrib.network.ip import (
|
|||||||
get_bridges,
|
get_bridges,
|
||||||
get_bridge_nics,
|
get_bridge_nics,
|
||||||
is_ip,
|
is_ip,
|
||||||
|
get_iface_addr,
|
||||||
|
get_host_ip
|
||||||
)
|
)
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.core.host import (
|
||||||
service_start,
|
service_start,
|
||||||
@ -39,6 +41,11 @@ from charmhelpers.fetch import (
|
|||||||
from charmhelpers.contrib.openstack.utils import (
|
from charmhelpers.contrib.openstack.utils import (
|
||||||
os_release,
|
os_release,
|
||||||
)
|
)
|
||||||
|
from pg_dir_context import (
|
||||||
|
_pg_dir_ips,
|
||||||
|
_pg_edge_ips,
|
||||||
|
_pg_gateway_ips
|
||||||
|
)
|
||||||
|
|
||||||
SOURCES_LIST = '/etc/apt/sources.list'
|
SOURCES_LIST = '/etc/apt/sources.list'
|
||||||
LXC_CONF = '/etc/libvirt/lxc.conf'
|
LXC_CONF = '/etc/libvirt/lxc.conf'
|
||||||
@ -109,8 +116,8 @@ def configure_analyst_opsvm():
|
|||||||
'''
|
'''
|
||||||
if not service_running('plumgrid'):
|
if not service_running('plumgrid'):
|
||||||
restart_pg()
|
restart_pg()
|
||||||
NS_ENTER = ('/opt/local/bin/nsenter -t $(ps ho pid --ppid '
|
NS_ENTER = ('/opt/local/bin/nsenter -t $(ps ho pid --ppid $(cat '
|
||||||
'$(cat /var/run/libvirt/lxc/plumgrid.pid)) -m -n -u -i -p ')
|
'/var/run/libvirt/lxc/plumgrid.pid)) -m -n -u -i -p ')
|
||||||
sigmund_stop = NS_ENTER + '/usr/bin/service plumgrid-sigmund stop'
|
sigmund_stop = NS_ENTER + '/usr/bin/service plumgrid-sigmund stop'
|
||||||
sigmund_status = NS_ENTER \
|
sigmund_status = NS_ENTER \
|
||||||
+ '/usr/bin/service plumgrid-sigmund status'
|
+ '/usr/bin/service plumgrid-sigmund status'
|
||||||
@ -248,7 +255,13 @@ def get_mgmt_interface():
|
|||||||
'''
|
'''
|
||||||
mgmt_interface = config('mgmt-interface')
|
mgmt_interface = config('mgmt-interface')
|
||||||
if not mgmt_interface:
|
if not mgmt_interface:
|
||||||
return get_iface_from_addr(unit_get('private-address'))
|
try:
|
||||||
|
return get_iface_from_addr(unit_get('private-address'))
|
||||||
|
except:
|
||||||
|
for bridge_interface in get_bridges():
|
||||||
|
if (get_host_ip(unit_get('private-address'))
|
||||||
|
in get_iface_addr(bridge_interface)):
|
||||||
|
return bridge_interface
|
||||||
elif interface_exists(mgmt_interface):
|
elif interface_exists(mgmt_interface):
|
||||||
return mgmt_interface
|
return mgmt_interface
|
||||||
else:
|
else:
|
||||||
@ -398,6 +411,141 @@ def post_pg_license():
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def sapi_post_ips():
|
||||||
|
pg_edge_ips = _pg_edge_ips()
|
||||||
|
pg_dir_ips = _pg_dir_ips()
|
||||||
|
pg_gateway_ips = _pg_gateway_ips()
|
||||||
|
pg_dir_ips.append(get_host_ip(unit_get('private-address')))
|
||||||
|
pg_edge_ips = '"edge_ips"' + ':' \
|
||||||
|
+ '"{}"'.format(','.join(str(i) for i in pg_edge_ips))
|
||||||
|
pg_dir_ips = '"director_ips"' + ':' \
|
||||||
|
+ '"{}"'.format(','.join(str(i) for i in pg_dir_ips))
|
||||||
|
pg_gateway_ips = '"gateway_ips"' + ':' \
|
||||||
|
+ '"{}"'.format(','.join(str(i) for i in pg_gateway_ips))
|
||||||
|
opsvm_ip = '"opsvm_ip"' + ':' + '"{}"'.format(config('opsvm-ip'))
|
||||||
|
virtual_ip = '"virtual_ip"' + ':' \
|
||||||
|
+ '"{}"'.format(config('plumgrid-virtual-ip'))
|
||||||
|
JSON_IPS = ','.join([pg_dir_ips, pg_edge_ips, pg_gateway_ips,
|
||||||
|
opsvm_ip, virtual_ip])
|
||||||
|
status = (
|
||||||
|
'curl -H \'Content-Type: application/json\' -X '
|
||||||
|
'PUT -d \'{{{0}}}\' http://{1}' + ':' + '{2}/v1/zones/{3}/allIps'
|
||||||
|
).format(JSON_IPS, config('lcm-ip'), config('sapi-port'),
|
||||||
|
config('sapi-zone'))
|
||||||
|
print "POST_IPS {}".format(status)
|
||||||
|
if 'success' in _exec_cmd_output(
|
||||||
|
status,
|
||||||
|
'No response from specified LCM IP!'):
|
||||||
|
log('Successfully posted Zone IPs to Solutions API server!')
|
||||||
|
|
||||||
|
|
||||||
|
def _exec_cmd_output(cmd=None, error_msg='Command exited with ERRORs',
|
||||||
|
fatal=False):
|
||||||
|
'''
|
||||||
|
Function to get output from bash command executed on the node.
|
||||||
|
'''
|
||||||
|
if cmd is None:
|
||||||
|
log("No command specified")
|
||||||
|
else:
|
||||||
|
if fatal:
|
||||||
|
return subprocess.check_output(cmd, shell=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(cmd, shell=True)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
log(error_msg)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def sapi_post_license():
|
||||||
|
username = '"user_name":' + '"{}"'.format(config('plumgrid-username'))
|
||||||
|
password = '"password":' + '"{}"'.format(config('plumgrid-password'))
|
||||||
|
license = '"license":' + '"{}"'.format(config('plumgrid-license-key'))
|
||||||
|
JSON_LICENSE = ','.join([username, password, license])
|
||||||
|
status = (
|
||||||
|
'curl -H \'Content-Type: application/json\' -X '
|
||||||
|
'PUT -d \'{{{0}}}\' http://{1}' + ':' + '{2}/v1/zones/{3}/pgLicense'
|
||||||
|
).format(JSON_LICENSE, config('lcm-ip'), config('sapi-port'),
|
||||||
|
config('sapi-zone'))
|
||||||
|
print "POST_LICENSE status: {}".format(status)
|
||||||
|
if 'success' in _exec_cmd_output(
|
||||||
|
status,
|
||||||
|
'No response from specified LCM IP!'):
|
||||||
|
log('Successfully posted license file for zone "{}"!'
|
||||||
|
.format(config('sapi-zone')))
|
||||||
|
|
||||||
|
|
||||||
|
def sapi_post_zone_info():
|
||||||
|
sol_name = '"solution_name":"Ubuntu OpenStack"'
|
||||||
|
sol_version = '"solution_version":"12"'
|
||||||
|
pg_ons_version = _exec_cmd_output(
|
||||||
|
'dpkg -l | grep plumgrid | awk \'{print $3}\' | '
|
||||||
|
'sed \'s/-/./\' | cut -f1 -d"-"',
|
||||||
|
'Unable to obtain PG ONS version'
|
||||||
|
).replace('\n', '')
|
||||||
|
pg_ons_version = \
|
||||||
|
'"pg_ons_version":"{}"'.format(pg_ons_version)
|
||||||
|
hypervisor = '"hypervisor":"Ubuntu"'
|
||||||
|
hypervisor_version = \
|
||||||
|
_exec_cmd_output('lsb_release -r | awk \'{print $2}\'',
|
||||||
|
'Unable to obtain solution version'
|
||||||
|
).replace('\n', '')
|
||||||
|
hypervisor_version = '"hypervisor_version":"{}"' \
|
||||||
|
.format(hypervisor_version)
|
||||||
|
kernel_version = _exec_cmd_output(
|
||||||
|
'uname -r',
|
||||||
|
'Unable to obtain kernal version').replace('\n', '')
|
||||||
|
kernel_version = \
|
||||||
|
'"kernel_version":"{}"'.format(kernel_version)
|
||||||
|
cloudapex_path = '/var/lib/libvirt/filesystems/plumgrid/' \
|
||||||
|
'opt/pg/web/cloudApex/modules/appCloudApex' \
|
||||||
|
'/appCloudApex.js'
|
||||||
|
if os.path.isfile(cloudapex_path):
|
||||||
|
pg_cloudapex_version = 'cat ' \
|
||||||
|
+ '{}'.format(cloudapex_path) \
|
||||||
|
+ ' | grep -i appversion | awk \'{print $2}\''
|
||||||
|
pg_cloudapex_version = \
|
||||||
|
_exec_cmd_output(pg_cloudapex_version,
|
||||||
|
'Unable to retrieve CloudApex version'
|
||||||
|
).replace('\n', '')
|
||||||
|
else:
|
||||||
|
log('CloudApex not installed!')
|
||||||
|
pg_cloudapex_version = ''
|
||||||
|
pg_cloudapex_version = \
|
||||||
|
'"pg_cloudapex_version":"{}"'.format(pg_cloudapex_version)
|
||||||
|
JSON_ZONE_INFO = ','.join([
|
||||||
|
sol_name,
|
||||||
|
sol_version,
|
||||||
|
pg_ons_version,
|
||||||
|
hypervisor,
|
||||||
|
hypervisor_version,
|
||||||
|
kernel_version,
|
||||||
|
pg_cloudapex_version,
|
||||||
|
])
|
||||||
|
status = (
|
||||||
|
'curl -H \'Content-Type: application/json\' -X '
|
||||||
|
'PUT -d \'{{{0}}}\' http://{1}:{2}/v1/zones/{3}/zoneinfo'
|
||||||
|
).format(JSON_ZONE_INFO, config('lcm-ip'), config('sapi-port'),
|
||||||
|
config('sapi-zone'))
|
||||||
|
print "ZONE_INFO status = {}".format(status)
|
||||||
|
if 'success' in _exec_cmd_output(
|
||||||
|
status,
|
||||||
|
'No response from specified LCM IP!'):
|
||||||
|
log('Successfully posted Zone IPs to Solutions API server!')
|
||||||
|
|
||||||
|
|
||||||
|
def is_zone_info_available():
|
||||||
|
zone_info = 'curl -H "Content-Type: application/json" -X GET '\
|
||||||
|
+ 'http://{}:8099/v1/zones/pgzone/zoneInfo'.format(config('lcm-ip'))
|
||||||
|
try:
|
||||||
|
status = subprocess.check_output(zone_info, shell=True)
|
||||||
|
if "success" in status:
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
log('No response from specified LCM IP')
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def load_iptables():
|
def load_iptables():
|
||||||
'''
|
'''
|
||||||
Loads iptables rules to allow all PLUMgrid communication.
|
Loads iptables rules to allow all PLUMgrid communication.
|
||||||
|
1
hooks/plumgrid-relation-changed
Symbolic link
1
hooks/plumgrid-relation-changed
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
pg_dir_hooks.py
|
1
hooks/plumgrid-relation-departed
Symbolic link
1
hooks/plumgrid-relation-departed
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
pg_dir_hooks.py
|
@ -33,7 +33,8 @@ TO_PATCH = [
|
|||||||
'config',
|
'config',
|
||||||
'load_iptables',
|
'load_iptables',
|
||||||
'status_set',
|
'status_set',
|
||||||
'configure_analyst_opsvm'
|
'configure_analyst_opsvm',
|
||||||
|
'sapi_post_zone_info'
|
||||||
]
|
]
|
||||||
NEUTRON_CONF_DIR = "/etc/neutron"
|
NEUTRON_CONF_DIR = "/etc/neutron"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user