Add package-upgrade action
The package-upgrade action performs package upgrades for the current OpenStack release. The code path used is similar to the openstack-upgrade action, with the difference being that package-upgrade will not execute if an openstack upgrade is available (based on the openstack-origin setting). This change includes a charm-helpers sync. Change-Id: I88ccffad7af2d2e9cddc1f6514ebd07898e117dc
This commit is contained in:
parent
1d132e68cc
commit
a61f5abc60
@ -18,6 +18,9 @@ openstack-upgrade:
|
||||
description: >-
|
||||
Perform OpenStack upgrades. Config option action-managed-upgrade must be
|
||||
set to True.
|
||||
package-upgrade:
|
||||
description: |
|
||||
Perform package upgrades for the current OpenStack release.
|
||||
instance-count:
|
||||
description: Return the number of VMs running on this unit.
|
||||
list-compute-nodes:
|
||||
|
1
actions/package-upgrade
Symbolic link
1
actions/package-upgrade
Symbolic link
@ -0,0 +1 @@
|
||||
package_upgrade.py
|
72
actions/package_upgrade.py
Executable file
72
actions/package_upgrade.py
Executable file
@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2022 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
_path = os.path.dirname(os.path.realpath(__file__))
|
||||
_hooks = os.path.abspath(os.path.join(_path, '../hooks'))
|
||||
|
||||
|
||||
def _add_path(path):
|
||||
if path not in sys.path:
|
||||
sys.path.insert(1, path)
|
||||
|
||||
|
||||
_add_path(_hooks)
|
||||
|
||||
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
do_action_package_upgrade,
|
||||
)
|
||||
from charmhelpers.core.hookenv import (
|
||||
relation_ids,
|
||||
)
|
||||
from nova_compute_utils import do_openstack_upgrade
|
||||
from nova_compute_hooks import (
|
||||
config_changed,
|
||||
CONFIGS,
|
||||
neutron_plugin_joined,
|
||||
nova_ceilometer_joined,
|
||||
)
|
||||
|
||||
|
||||
def package_upgrade():
|
||||
"""Perform package upgrade within the current OpenStack release.
|
||||
|
||||
In order to prevent this action from upgrading to a new release of
|
||||
OpenStack, package upgrades are not run if a new OpenStack release is
|
||||
available. See source of do_action_package_upgrade() for this check.
|
||||
|
||||
Upgrades packages and sets the corresponding action status as a result."""
|
||||
|
||||
if (do_action_package_upgrade('nova-common',
|
||||
do_openstack_upgrade,
|
||||
CONFIGS)):
|
||||
# we should restart the container scoped (subordinate) plugins after a
|
||||
# managed openstack upgrade see: BUG#1835557
|
||||
for rid in relation_ids('neutron-plugin'):
|
||||
neutron_plugin_joined(rid, remote_restart=True)
|
||||
for rid in relation_ids('nova-ceilometer'):
|
||||
nova_ceilometer_joined(rid, remote_restart=True)
|
||||
# NOTE(ajkavanagh) - if unit is paused (usually true for managed
|
||||
# upgrade) then the config_changed() function is a no-op
|
||||
config_changed()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
package_upgrade()
|
@ -14,30 +14,15 @@
|
||||
|
||||
# Bootstrap charm-helpers, installing its dependencies if necessary using
|
||||
# only standard libraries.
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
try:
|
||||
import six # NOQA:F401
|
||||
except ImportError:
|
||||
if sys.version_info.major == 2:
|
||||
subprocess.check_call(['apt-get', 'install', '-y', 'python-six'])
|
||||
else:
|
||||
subprocess.check_call(['apt-get', 'install', '-y', 'python3-six'])
|
||||
import six # NOQA:F401
|
||||
|
||||
try:
|
||||
import yaml # NOQA:F401
|
||||
except ImportError:
|
||||
if sys.version_info.major == 2:
|
||||
subprocess.check_call(['apt-get', 'install', '-y', 'python-yaml'])
|
||||
else:
|
||||
subprocess.check_call(['apt-get', 'install', '-y', 'python3-yaml'])
|
||||
subprocess.check_call(['apt-get', 'install', '-y', 'python3-yaml'])
|
||||
import yaml # NOQA:F401
|
||||
|
||||
|
||||
|
@ -16,9 +16,6 @@ import inspect
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import six
|
||||
from six.moves import zip
|
||||
|
||||
import charmhelpers.core.unitdata
|
||||
|
||||
|
||||
@ -149,10 +146,7 @@ class CommandLine(object):
|
||||
def run(self):
|
||||
"Run cli, processing arguments and executing subcommands."
|
||||
arguments = self.argument_parser.parse_args()
|
||||
if six.PY2:
|
||||
argspec = inspect.getargspec(arguments.func)
|
||||
else:
|
||||
argspec = inspect.getfullargspec(arguments.func)
|
||||
argspec = inspect.getfullargspec(arguments.func)
|
||||
vargs = []
|
||||
for arg in argspec.args:
|
||||
vargs.append(getattr(arguments, arg))
|
||||
@ -177,10 +171,7 @@ def describe_arguments(func):
|
||||
Analyze a function's signature and return a data structure suitable for
|
||||
passing in as arguments to an argparse parser's add_argument() method."""
|
||||
|
||||
if six.PY2:
|
||||
argspec = inspect.getargspec(func)
|
||||
else:
|
||||
argspec = inspect.getfullargspec(func)
|
||||
argspec = inspect.getfullargspec(func)
|
||||
# we should probably raise an exception somewhere if func includes **kwargs
|
||||
if argspec.defaults:
|
||||
positional_args = argspec.args[:-len(argspec.defaults)]
|
||||
|
@ -32,8 +32,6 @@ import time
|
||||
|
||||
from socket import gethostname as get_unit_hostname
|
||||
|
||||
import six
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
relation_ids,
|
||||
@ -125,16 +123,16 @@ def is_crm_dc():
|
||||
"""
|
||||
cmd = ['crm', 'status']
|
||||
try:
|
||||
status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||
if not isinstance(status, six.text_type):
|
||||
status = six.text_type(status, "utf-8")
|
||||
status = subprocess.check_output(
|
||||
cmd, stderr=subprocess.STDOUT).decode('utf-8')
|
||||
except subprocess.CalledProcessError as ex:
|
||||
raise CRMDCNotFound(str(ex))
|
||||
|
||||
current_dc = ''
|
||||
for line in status.split('\n'):
|
||||
if line.startswith('Current DC'):
|
||||
# Current DC: juju-lytrusty-machine-2 (168108163) - partition with quorum
|
||||
# Current DC: juju-lytrusty-machine-2 (168108163)
|
||||
# - partition with quorum
|
||||
current_dc = line.split(':')[1].split()[0]
|
||||
if current_dc == get_unit_hostname():
|
||||
return True
|
||||
@ -158,9 +156,8 @@ def is_crm_leader(resource, retry=False):
|
||||
return is_crm_dc()
|
||||
cmd = ['crm', 'resource', 'show', resource]
|
||||
try:
|
||||
status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||
if not isinstance(status, six.text_type):
|
||||
status = six.text_type(status, "utf-8")
|
||||
status = subprocess.check_output(
|
||||
cmd, stderr=subprocess.STDOUT).decode('utf-8')
|
||||
except subprocess.CalledProcessError:
|
||||
status = None
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import six
|
||||
import subprocess
|
||||
|
||||
|
||||
@ -95,9 +94,7 @@ class ApacheConfContext(object):
|
||||
settings = utils.get_settings('apache')
|
||||
ctxt = settings['hardening']
|
||||
|
||||
out = subprocess.check_output(['apache2', '-v'])
|
||||
if six.PY3:
|
||||
out = out.decode('utf-8')
|
||||
out = subprocess.check_output(['apache2', '-v']).decode('utf-8')
|
||||
ctxt['apache_version'] = re.search(r'.+version: Apache/(.+?)\s.+',
|
||||
out).group(1)
|
||||
ctxt['apache_icondir'] = '/usr/share/apache2/icons/'
|
||||
|
@ -15,8 +15,6 @@
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import six
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
INFO,
|
||||
@ -35,7 +33,7 @@ class DisabledModuleAudit(BaseAudit):
|
||||
def __init__(self, modules):
|
||||
if modules is None:
|
||||
self.modules = []
|
||||
elif isinstance(modules, six.string_types):
|
||||
elif isinstance(modules, str):
|
||||
self.modules = [modules]
|
||||
else:
|
||||
self.modules = modules
|
||||
@ -68,9 +66,7 @@ class DisabledModuleAudit(BaseAudit):
|
||||
@staticmethod
|
||||
def _get_loaded_modules():
|
||||
"""Returns the modules which are enabled in Apache."""
|
||||
output = subprocess.check_output(['apache2ctl', '-M'])
|
||||
if six.PY3:
|
||||
output = output.decode('utf-8')
|
||||
output = subprocess.check_output(['apache2ctl', '-M']).decode('utf-8')
|
||||
modules = []
|
||||
for line in output.splitlines():
|
||||
# Each line of the enabled module output looks like:
|
||||
|
@ -12,9 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import # required for external apt import
|
||||
from six import string_types
|
||||
|
||||
from charmhelpers.fetch import (
|
||||
apt_cache,
|
||||
apt_purge
|
||||
@ -51,7 +48,7 @@ class RestrictedPackages(BaseAudit):
|
||||
|
||||
def __init__(self, pkgs, **kwargs):
|
||||
super(RestrictedPackages, self).__init__(**kwargs)
|
||||
if isinstance(pkgs, string_types) or not hasattr(pkgs, '__iter__'):
|
||||
if isinstance(pkgs, str) or not hasattr(pkgs, '__iter__'):
|
||||
self.pkgs = pkgs.split()
|
||||
else:
|
||||
self.pkgs = pkgs
|
||||
|
@ -23,7 +23,6 @@ from subprocess import (
|
||||
check_call,
|
||||
)
|
||||
from traceback import format_exc
|
||||
from six import string_types
|
||||
from stat import (
|
||||
S_ISGID,
|
||||
S_ISUID
|
||||
@ -63,7 +62,7 @@ class BaseFileAudit(BaseAudit):
|
||||
"""
|
||||
super(BaseFileAudit, self).__init__(*args, **kwargs)
|
||||
self.always_comply = always_comply
|
||||
if isinstance(paths, string_types) or not hasattr(paths, '__iter__'):
|
||||
if isinstance(paths, str) or not hasattr(paths, '__iter__'):
|
||||
self.paths = [paths]
|
||||
else:
|
||||
self.paths = paths
|
||||
|
@ -12,8 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import six
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -53,18 +51,17 @@ def harden(overrides=None):
|
||||
overrides = []
|
||||
|
||||
def _harden_inner1(f):
|
||||
# As this has to be py2.7 compat, we can't use nonlocal. Use a trick
|
||||
# to capture the dictionary that can then be updated.
|
||||
_logged = {'done': False}
|
||||
_logged = False
|
||||
|
||||
def _harden_inner2(*args, **kwargs):
|
||||
# knock out hardening via a config var; normally it won't get
|
||||
# disabled.
|
||||
nonlocal _logged
|
||||
if _DISABLE_HARDENING_FOR_UNIT_TEST:
|
||||
return f(*args, **kwargs)
|
||||
if not _logged['done']:
|
||||
if not _logged:
|
||||
log("Hardening function '%s'" % (f.__name__), level=DEBUG)
|
||||
_logged['done'] = True
|
||||
_logged = True
|
||||
RUN_CATALOG = OrderedDict([('os', run_os_checks),
|
||||
('ssh', run_ssh_checks),
|
||||
('mysql', run_mysql_checks),
|
||||
@ -74,7 +71,7 @@ def harden(overrides=None):
|
||||
if enabled:
|
||||
modules_to_run = []
|
||||
# modules will always be performed in the following order
|
||||
for module, func in six.iteritems(RUN_CATALOG):
|
||||
for module, func in RUN_CATALOG.items():
|
||||
if module in enabled:
|
||||
enabled.remove(module)
|
||||
modules_to_run.append(func)
|
||||
|
@ -12,8 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from six import string_types
|
||||
|
||||
from charmhelpers.contrib.hardening.audits.file import TemplatedFile
|
||||
from charmhelpers.contrib.hardening.host import TEMPLATES_DIR
|
||||
from charmhelpers.contrib.hardening import utils
|
||||
@ -41,7 +39,7 @@ class LoginContext(object):
|
||||
# a string assume it to be octal and turn it into an octal
|
||||
# string.
|
||||
umask = settings['environment']['umask']
|
||||
if not isinstance(umask, string_types):
|
||||
if not isinstance(umask, str):
|
||||
umask = '%s' % oct(umask)
|
||||
|
||||
ctxt = {
|
||||
|
@ -15,7 +15,6 @@
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import six
|
||||
import subprocess
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -183,9 +182,9 @@ class SysCtlHardeningContext(object):
|
||||
|
||||
ctxt['sysctl'][key] = d[2] or None
|
||||
|
||||
# Translate for python3
|
||||
return {'sysctl_settings':
|
||||
[(k, v) for k, v in six.iteritems(ctxt['sysctl'])]}
|
||||
return {
|
||||
'sysctl_settings': [(k, v) for k, v in ctxt['sysctl'].items()]
|
||||
}
|
||||
|
||||
|
||||
class SysctlConf(TemplatedFile):
|
||||
|
@ -12,7 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import six
|
||||
import subprocess
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -82,6 +81,6 @@ class MySQLConfContext(object):
|
||||
"""
|
||||
def __call__(self):
|
||||
settings = utils.get_settings('mysql')
|
||||
# Translate for python3
|
||||
return {'mysql_settings':
|
||||
[(k, v) for k, v in six.iteritems(settings['security'])]}
|
||||
return {
|
||||
'mysql_settings': [(k, v) for k, v in settings['security'].items()]
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import six
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
@ -27,10 +26,7 @@ except ImportError:
|
||||
from charmhelpers.fetch import apt_install
|
||||
from charmhelpers.fetch import apt_update
|
||||
apt_update(fatal=True)
|
||||
if six.PY2:
|
||||
apt_install('python-jinja2', fatal=True)
|
||||
else:
|
||||
apt_install('python3-jinja2', fatal=True)
|
||||
apt_install('python3-jinja2', fatal=True)
|
||||
from jinja2 import FileSystemLoader, Environment
|
||||
|
||||
|
||||
|
@ -16,7 +16,6 @@ import glob
|
||||
import grp
|
||||
import os
|
||||
import pwd
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -91,7 +90,7 @@ def _apply_overrides(settings, overrides, schema):
|
||||
:returns: dictionary of modules config with user overrides applied.
|
||||
"""
|
||||
if overrides:
|
||||
for k, v in six.iteritems(overrides):
|
||||
for k, v in overrides.items():
|
||||
if k in schema:
|
||||
if schema[k] is None:
|
||||
settings[k] = v
|
||||
|
@ -15,7 +15,6 @@
|
||||
import glob
|
||||
import re
|
||||
import subprocess
|
||||
import six
|
||||
import socket
|
||||
|
||||
from functools import partial
|
||||
@ -39,20 +38,14 @@ try:
|
||||
import netifaces
|
||||
except ImportError:
|
||||
apt_update(fatal=True)
|
||||
if six.PY2:
|
||||
apt_install('python-netifaces', fatal=True)
|
||||
else:
|
||||
apt_install('python3-netifaces', fatal=True)
|
||||
apt_install('python3-netifaces', fatal=True)
|
||||
import netifaces
|
||||
|
||||
try:
|
||||
import netaddr
|
||||
except ImportError:
|
||||
apt_update(fatal=True)
|
||||
if six.PY2:
|
||||
apt_install('python-netaddr', fatal=True)
|
||||
else:
|
||||
apt_install('python3-netaddr', fatal=True)
|
||||
apt_install('python3-netaddr', fatal=True)
|
||||
import netaddr
|
||||
|
||||
|
||||
@ -462,15 +455,12 @@ def ns_query(address):
|
||||
try:
|
||||
import dns.resolver
|
||||
except ImportError:
|
||||
if six.PY2:
|
||||
apt_install('python-dnspython', fatal=True)
|
||||
else:
|
||||
apt_install('python3-dnspython', fatal=True)
|
||||
apt_install('python3-dnspython', fatal=True)
|
||||
import dns.resolver
|
||||
|
||||
if isinstance(address, dns.name.Name):
|
||||
rtype = 'PTR'
|
||||
elif isinstance(address, six.string_types):
|
||||
elif isinstance(address, str):
|
||||
rtype = 'A'
|
||||
else:
|
||||
return None
|
||||
@ -513,10 +503,7 @@ def get_hostname(address, fqdn=True):
|
||||
try:
|
||||
import dns.reversename
|
||||
except ImportError:
|
||||
if six.PY2:
|
||||
apt_install("python-dnspython", fatal=True)
|
||||
else:
|
||||
apt_install("python3-dnspython", fatal=True)
|
||||
apt_install("python3-dnspython", fatal=True)
|
||||
import dns.reversename
|
||||
|
||||
rev = dns.reversename.from_address(address)
|
||||
|
@ -17,7 +17,6 @@ import collections
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import six
|
||||
import subprocess
|
||||
|
||||
from charmhelpers import deprecate
|
||||
@ -367,10 +366,7 @@ def add_ovsbridge_linuxbridge(name, bridge, ifdata=None, portdata=None):
|
||||
try:
|
||||
import netifaces
|
||||
except ImportError:
|
||||
if six.PY2:
|
||||
apt_install('python-netifaces', fatal=True)
|
||||
else:
|
||||
apt_install('python3-netifaces', fatal=True)
|
||||
apt_install('python3-netifaces', fatal=True)
|
||||
import netifaces
|
||||
|
||||
# NOTE(jamespage):
|
||||
|
@ -126,24 +126,27 @@ class SimpleOVSDB(object):
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, tool):
|
||||
def __init__(self, tool, args=None):
|
||||
"""SimpleOVSDB constructor.
|
||||
|
||||
:param tool: Which tool with database commands to operate on.
|
||||
Usually one of `ovs-vsctl`, `ovn-nbctl`, `ovn-sbctl`
|
||||
:type tool: str
|
||||
:param args: Extra arguments to pass to the tool
|
||||
:type args: Optional[List[str]]
|
||||
"""
|
||||
if tool not in self._tool_table_map:
|
||||
raise RuntimeError(
|
||||
'tool must be one of "{}"'.format(self._tool_table_map.keys()))
|
||||
self._tool = tool
|
||||
self._args = args
|
||||
|
||||
def __getattr__(self, table):
|
||||
if table not in self._tool_table_map[self._tool]:
|
||||
raise AttributeError(
|
||||
'table "{}" not known for use with "{}"'
|
||||
.format(table, self._tool))
|
||||
return self.Table(self._tool, table)
|
||||
return self.Table(self._tool, table, args=self._args)
|
||||
|
||||
class Table(object):
|
||||
"""Methods to interact with contents of OVSDB tables.
|
||||
@ -153,14 +156,17 @@ class SimpleOVSDB(object):
|
||||
JSON output.
|
||||
"""
|
||||
|
||||
def __init__(self, tool, table):
|
||||
def __init__(self, tool, table, args=None):
|
||||
"""SimpleOVSDBTable constructor.
|
||||
|
||||
:param table: Which table to operate on
|
||||
:type table: str
|
||||
:param args: Extra arguments to pass to the tool
|
||||
:type args: Optional[List[str]]
|
||||
"""
|
||||
self._tool = tool
|
||||
self._table = table
|
||||
self._args = args
|
||||
|
||||
def _deserialize_ovsdb(self, data):
|
||||
"""Deserialize OVSDB RFC7047 section 5.1 data.
|
||||
@ -215,7 +221,10 @@ class SimpleOVSDB(object):
|
||||
:returns: Dictionary with data
|
||||
:rtype: Dict[str, any]
|
||||
"""
|
||||
cmd = [self._tool, '-f', 'json', 'find', self._table]
|
||||
cmd = [self._tool]
|
||||
if self._args:
|
||||
cmd.extend(self._args)
|
||||
cmd.extend(['-f', 'json', 'find', self._table])
|
||||
if condition:
|
||||
cmd.append(condition)
|
||||
output = utils._run(*cmd)
|
||||
|
@ -30,8 +30,6 @@ from subprocess import (
|
||||
check_output,
|
||||
CalledProcessError)
|
||||
|
||||
import six
|
||||
|
||||
import charmhelpers.contrib.storage.linux.ceph as ch_ceph
|
||||
|
||||
from charmhelpers.contrib.openstack.audits.openstack_security_guide import (
|
||||
@ -130,10 +128,7 @@ except ImportError:
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
if six.PY2:
|
||||
apt_install('python-psutil', fatal=True)
|
||||
else:
|
||||
apt_install('python3-psutil', fatal=True)
|
||||
apt_install('python3-psutil', fatal=True)
|
||||
import psutil
|
||||
|
||||
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
|
||||
@ -150,10 +145,7 @@ def ensure_packages(packages):
|
||||
|
||||
|
||||
def context_complete(ctxt):
|
||||
_missing = []
|
||||
for k, v in six.iteritems(ctxt):
|
||||
if v is None or v == '':
|
||||
_missing.append(k)
|
||||
_missing = [k for k, v in ctxt.items() if v is None or v == '']
|
||||
|
||||
if _missing:
|
||||
log('Missing required data: %s' % ' '.join(_missing), level=INFO)
|
||||
@ -180,7 +172,7 @@ class OSContextGenerator(object):
|
||||
# Fresh start
|
||||
self.complete = False
|
||||
self.missing_data = []
|
||||
for k, v in six.iteritems(ctxt):
|
||||
for k, v in ctxt.items():
|
||||
if v is None or v == '':
|
||||
if k not in self.missing_data:
|
||||
self.missing_data.append(k)
|
||||
@ -1111,10 +1103,14 @@ class ApacheSSLContext(OSContextGenerator):
|
||||
endpoint = resolve_address(net_type)
|
||||
addresses.append((addr, endpoint))
|
||||
|
||||
return sorted(set(addresses))
|
||||
# Log the set of addresses to have a trail log and capture if tuples
|
||||
# change over time in the same unit (LP: #1952414).
|
||||
sorted_addresses = sorted(set(addresses))
|
||||
log('get_network_addresses: {}'.format(sorted_addresses))
|
||||
return sorted_addresses
|
||||
|
||||
def __call__(self):
|
||||
if isinstance(self.external_ports, six.string_types):
|
||||
if isinstance(self.external_ports, str):
|
||||
self.external_ports = [self.external_ports]
|
||||
|
||||
if not self.external_ports or not https():
|
||||
@ -1531,9 +1527,9 @@ class SubordinateConfigContext(OSContextGenerator):
|
||||
continue
|
||||
|
||||
sub_config = sub_config[self.config_file]
|
||||
for k, v in six.iteritems(sub_config):
|
||||
for k, v in sub_config.items():
|
||||
if k == 'sections':
|
||||
for section, config_list in six.iteritems(v):
|
||||
for section, config_list in v.items():
|
||||
log("adding section '%s'" % (section),
|
||||
level=DEBUG)
|
||||
if ctxt[k].get(section):
|
||||
@ -1887,8 +1883,11 @@ class DataPortContext(NeutronPortContext):
|
||||
normalized.update({port: port for port in resolved
|
||||
if port in ports})
|
||||
if resolved:
|
||||
return {normalized[port]: bridge for port, bridge in
|
||||
six.iteritems(portmap) if port in normalized.keys()}
|
||||
return {
|
||||
normalized[port]: bridge
|
||||
for port, bridge in portmap.items()
|
||||
if port in normalized.keys()
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
@ -2291,15 +2290,10 @@ class HostInfoContext(OSContextGenerator):
|
||||
name = name or socket.gethostname()
|
||||
fqdn = ''
|
||||
|
||||
if six.PY2:
|
||||
exc = socket.error
|
||||
else:
|
||||
exc = OSError
|
||||
|
||||
try:
|
||||
addrs = socket.getaddrinfo(
|
||||
name, None, 0, socket.SOCK_DGRAM, 0, socket.AI_CANONNAME)
|
||||
except exc:
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
for addr in addrs:
|
||||
@ -2416,12 +2410,12 @@ class DHCPAgentContext(OSContextGenerator):
|
||||
existing_ovs_use_veth = None
|
||||
# If there is a dhcp_agent.ini file read the current setting
|
||||
if os.path.isfile(DHCP_AGENT_INI):
|
||||
# config_ini does the right thing and returns None if the setting is
|
||||
# commented.
|
||||
# config_ini does the right thing and returns None if the setting
|
||||
# is commented.
|
||||
existing_ovs_use_veth = (
|
||||
config_ini(DHCP_AGENT_INI)["DEFAULT"].get("ovs_use_veth"))
|
||||
# Convert to Bool if necessary
|
||||
if isinstance(existing_ovs_use_veth, six.string_types):
|
||||
if isinstance(existing_ovs_use_veth, str):
|
||||
return bool_from_string(existing_ovs_use_veth)
|
||||
return existing_ovs_use_veth
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright 2017 Canonical Ltd
|
||||
#
|
||||
@ -14,7 +13,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import six
|
||||
from charmhelpers.fetch import apt_install
|
||||
from charmhelpers.contrib.openstack.context import IdentityServiceContext
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -117,10 +115,7 @@ class KeystoneManager2(KeystoneManager):
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient import session
|
||||
except ImportError:
|
||||
if six.PY2:
|
||||
apt_install(["python-keystoneclient"], fatal=True)
|
||||
else:
|
||||
apt_install(["python3-keystoneclient"], fatal=True)
|
||||
apt_install(["python3-keystoneclient"], fatal=True)
|
||||
|
||||
from keystoneclient.v2_0 import client
|
||||
from keystoneclient.auth.identity import v2
|
||||
@ -151,10 +146,7 @@ class KeystoneManager3(KeystoneManager):
|
||||
from keystoneclient import session
|
||||
from keystoneclient.auth.identity import v3
|
||||
except ImportError:
|
||||
if six.PY2:
|
||||
apt_install(["python-keystoneclient"], fatal=True)
|
||||
else:
|
||||
apt_install(["python3-keystoneclient"], fatal=True)
|
||||
apt_install(["python3-keystoneclient"], fatal=True)
|
||||
|
||||
from keystoneclient.v3 import client
|
||||
from keystoneclient.auth import token_endpoint
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
# Various utilities for dealing with Neutron and the renaming from Quantum.
|
||||
|
||||
import six
|
||||
from subprocess import check_output
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -349,11 +348,4 @@ def parse_vlan_range_mappings(mappings):
|
||||
Returns dict of the form {provider: (start, end)}.
|
||||
"""
|
||||
_mappings = parse_mappings(mappings)
|
||||
if not _mappings:
|
||||
return {}
|
||||
|
||||
mappings = {}
|
||||
for p, r in six.iteritems(_mappings):
|
||||
mappings[p] = tuple(r.split(':'))
|
||||
|
||||
return mappings
|
||||
return {p: tuple(r.split(':')) for p, r in _mappings.items()}
|
||||
|
@ -15,7 +15,6 @@
|
||||
import collections
|
||||
import contextlib
|
||||
import os
|
||||
import six
|
||||
import shutil
|
||||
import yaml
|
||||
import zipfile
|
||||
@ -204,12 +203,6 @@ class BadPolicyYamlFile(Exception):
|
||||
return self.log_message
|
||||
|
||||
|
||||
if six.PY2:
|
||||
BadZipFile = zipfile.BadZipfile
|
||||
else:
|
||||
BadZipFile = zipfile.BadZipFile
|
||||
|
||||
|
||||
def is_policyd_override_valid_on_this_release(openstack_release):
|
||||
"""Check that the charm is running on at least Ubuntu Xenial, and at
|
||||
least the queens release.
|
||||
@ -487,10 +480,10 @@ def read_and_validate_yaml(stream_or_doc, blacklist_keys=None):
|
||||
if blacklisted_keys_present:
|
||||
raise BadPolicyYamlFile("blacklisted keys {} present."
|
||||
.format(", ".join(blacklisted_keys_present)))
|
||||
if not all(isinstance(k, six.string_types) for k in keys):
|
||||
if not all(isinstance(k, str) for k in keys):
|
||||
raise BadPolicyYamlFile("keys in yaml aren't all strings?")
|
||||
# check that the dictionary looks like a mapping of str to str
|
||||
if not all(isinstance(v, six.string_types) for v in doc.values()):
|
||||
if not all(isinstance(v, str) for v in doc.values()):
|
||||
raise BadPolicyYamlFile("values in yaml aren't all strings?")
|
||||
return doc
|
||||
|
||||
@ -530,8 +523,7 @@ def clean_policyd_dir_for(service, keep_paths=None, user=None, group=None):
|
||||
hookenv.log("Cleaning path: {}".format(path), level=hookenv.DEBUG)
|
||||
if not os.path.exists(path):
|
||||
ch_host.mkdir(path, owner=_user, group=_group, perms=0o775)
|
||||
_scanner = os.scandir if hasattr(os, 'scandir') else _fallback_scandir
|
||||
for direntry in _scanner(path):
|
||||
for direntry in os.scandir(path):
|
||||
# see if the path should be kept.
|
||||
if direntry.path in keep_paths:
|
||||
continue
|
||||
@ -558,36 +550,6 @@ def maybe_create_directory_for(path, user, group):
|
||||
ch_host.mkdir(_dir, owner=user, group=group, perms=0o775)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _fallback_scandir(path):
|
||||
"""Fallback os.scandir implementation.
|
||||
|
||||
provide a fallback implementation of os.scandir if this module ever gets
|
||||
used in a py2 or py34 charm. Uses os.listdir() to get the names in the path,
|
||||
and then mocks the is_dir() function using os.path.isdir() to check for
|
||||
directory.
|
||||
|
||||
:param path: the path to list the directories for
|
||||
:type path: str
|
||||
:returns: Generator that provides _FBDirectory objects
|
||||
:rtype: ContextManager[_FBDirectory]
|
||||
"""
|
||||
for f in os.listdir(path):
|
||||
yield _FBDirectory(f)
|
||||
|
||||
|
||||
class _FBDirectory(object):
|
||||
"""Mock a scandir Directory object with enough to use in
|
||||
clean_policyd_dir_for
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def is_dir(self):
|
||||
return os.path.isdir(self.path)
|
||||
|
||||
|
||||
def path_for_policy_file(service, name):
|
||||
"""Return the full path for a policy.d file that will be written to the
|
||||
service's policy.d directory.
|
||||
@ -768,7 +730,7 @@ def process_policy_resource_file(resource_file,
|
||||
_group)
|
||||
# Every thing worked, so we mark up a success.
|
||||
completed = True
|
||||
except (BadZipFile, BadPolicyZipFile, BadPolicyYamlFile) as e:
|
||||
except (zipfile.BadZipFile, BadPolicyZipFile, BadPolicyYamlFile) as e:
|
||||
hookenv.log("Processing {} failed: {}".format(resource_file, str(e)),
|
||||
level=POLICYD_LOG_LEVEL_DEFAULT)
|
||||
except IOError as e:
|
||||
|
@ -22,6 +22,8 @@ Listen {{ ext_port }}
|
||||
ProxyPassReverse / http://localhost:{{ int }}/
|
||||
ProxyPreserveHost on
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
</VirtualHost>
|
||||
{% endfor -%}
|
||||
<Proxy *>
|
||||
|
@ -22,6 +22,8 @@ Listen {{ ext_port }}
|
||||
ProxyPassReverse / http://localhost:{{ int }}/
|
||||
ProxyPreserveHost on
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
</VirtualHost>
|
||||
{% endfor -%}
|
||||
<Proxy *>
|
||||
|
@ -20,6 +20,8 @@ Listen {{ public_port }}
|
||||
WSGIScriptAlias / {{ script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
@ -46,6 +48,8 @@ Listen {{ public_port }}
|
||||
WSGIScriptAlias / {{ admin_script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
@ -72,6 +76,8 @@ Listen {{ public_port }}
|
||||
WSGIScriptAlias / {{ public_script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
|
@ -20,6 +20,8 @@ Listen {{ public_port }}
|
||||
WSGIScriptAlias / {{ script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
@ -46,6 +48,8 @@ Listen {{ public_port }}
|
||||
WSGIScriptAlias / {{ admin_script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
@ -72,6 +76,8 @@ Listen {{ public_port }}
|
||||
WSGIScriptAlias / {{ public_script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
|
@ -14,8 +14,6 @@
|
||||
|
||||
import os
|
||||
|
||||
import six
|
||||
|
||||
from charmhelpers.fetch import apt_install, apt_update
|
||||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
@ -29,10 +27,7 @@ try:
|
||||
from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions
|
||||
except ImportError:
|
||||
apt_update(fatal=True)
|
||||
if six.PY2:
|
||||
apt_install('python-jinja2', fatal=True)
|
||||
else:
|
||||
apt_install('python3-jinja2', fatal=True)
|
||||
apt_install('python3-jinja2', fatal=True)
|
||||
from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions
|
||||
|
||||
|
||||
@ -62,7 +57,7 @@ def get_loader(templates_dir, os_release):
|
||||
order by OpenStack release.
|
||||
"""
|
||||
tmpl_dirs = [(rel, os.path.join(templates_dir, rel))
|
||||
for rel in six.itervalues(OPENSTACK_CODENAMES)]
|
||||
for rel in OPENSTACK_CODENAMES.values()]
|
||||
|
||||
if not os.path.isdir(templates_dir):
|
||||
log('Templates directory not found @ %s.' % templates_dir,
|
||||
@ -225,10 +220,7 @@ class OSConfigRenderer(object):
|
||||
# if this code is running, the object is created pre-install hook.
|
||||
# jinja2 shouldn't get touched until the module is reloaded on next
|
||||
# hook execution, with proper jinja2 bits successfully imported.
|
||||
if six.PY2:
|
||||
apt_install('python-jinja2')
|
||||
else:
|
||||
apt_install('python3-jinja2')
|
||||
apt_install('python3-jinja2')
|
||||
|
||||
def register(self, config_file, contexts, config_template=None):
|
||||
"""
|
||||
@ -318,9 +310,7 @@ class OSConfigRenderer(object):
|
||||
log('Config not registered: %s' % config_file, level=ERROR)
|
||||
raise OSConfigException
|
||||
|
||||
_out = self.render(config_file)
|
||||
if six.PY3:
|
||||
_out = _out.encode('UTF-8')
|
||||
_out = self.render(config_file).encode('UTF-8')
|
||||
|
||||
with open(config_file, 'wb') as out:
|
||||
out.write(_out)
|
||||
@ -331,7 +321,8 @@ class OSConfigRenderer(object):
|
||||
"""
|
||||
Write out all registered config files.
|
||||
"""
|
||||
[self.write(k) for k in six.iterkeys(self.templates)]
|
||||
for k in self.templates.keys():
|
||||
self.write(k)
|
||||
|
||||
def set_release(self, openstack_release):
|
||||
"""
|
||||
@ -347,8 +338,8 @@ class OSConfigRenderer(object):
|
||||
Returns a list of context interfaces that yield a complete context.
|
||||
'''
|
||||
interfaces = []
|
||||
[interfaces.extend(i.complete_contexts())
|
||||
for i in six.itervalues(self.templates)]
|
||||
for i in self.templates.values():
|
||||
interfaces.extend(i.complete_contexts())
|
||||
return interfaces
|
||||
|
||||
def get_incomplete_context_data(self, interfaces):
|
||||
@ -360,7 +351,7 @@ class OSConfigRenderer(object):
|
||||
'''
|
||||
incomplete_context_data = {}
|
||||
|
||||
for i in six.itervalues(self.templates):
|
||||
for i in self.templates.values():
|
||||
for context in i.contexts:
|
||||
for interface in interfaces:
|
||||
related = False
|
||||
|
@ -25,7 +25,6 @@ import re
|
||||
import itertools
|
||||
import functools
|
||||
|
||||
import six
|
||||
import traceback
|
||||
import uuid
|
||||
import yaml
|
||||
@ -362,6 +361,8 @@ def get_os_codename_install_source(src):
|
||||
rel = ''
|
||||
if src is None:
|
||||
return rel
|
||||
if src in OPENSTACK_RELEASES:
|
||||
return src
|
||||
if src in ['distro', 'distro-proposed', 'proposed']:
|
||||
try:
|
||||
rel = UBUNTU_OPENSTACK_RELEASE[ubuntu_rel]
|
||||
@ -401,7 +402,7 @@ def get_os_codename_version(vers):
|
||||
|
||||
def get_os_version_codename(codename, version_map=OPENSTACK_CODENAMES):
|
||||
'''Determine OpenStack version number from codename.'''
|
||||
for k, v in six.iteritems(version_map):
|
||||
for k, v in version_map.items():
|
||||
if v == codename:
|
||||
return k
|
||||
e = 'Could not derive OpenStack version for '\
|
||||
@ -411,7 +412,8 @@ def get_os_version_codename(codename, version_map=OPENSTACK_CODENAMES):
|
||||
|
||||
def get_os_version_codename_swift(codename):
|
||||
'''Determine OpenStack version number of swift from codename.'''
|
||||
for k, v in six.iteritems(SWIFT_CODENAMES):
|
||||
# for k, v in six.iteritems(SWIFT_CODENAMES):
|
||||
for k, v in SWIFT_CODENAMES.items():
|
||||
if k == codename:
|
||||
return v[-1]
|
||||
e = 'Could not derive swift version for '\
|
||||
@ -421,17 +423,17 @@ def get_os_version_codename_swift(codename):
|
||||
|
||||
def get_swift_codename(version):
|
||||
'''Determine OpenStack codename that corresponds to swift version.'''
|
||||
codenames = [k for k, v in six.iteritems(SWIFT_CODENAMES) if version in v]
|
||||
codenames = [k for k, v in SWIFT_CODENAMES.items() if version in v]
|
||||
|
||||
if len(codenames) > 1:
|
||||
# If more than one release codename contains this version we determine
|
||||
# the actual codename based on the highest available install source.
|
||||
for codename in reversed(codenames):
|
||||
releases = UBUNTU_OPENSTACK_RELEASE
|
||||
release = [k for k, v in six.iteritems(releases) if codename in v]
|
||||
ret = subprocess.check_output(['apt-cache', 'policy', 'swift'])
|
||||
if six.PY3:
|
||||
ret = ret.decode('UTF-8')
|
||||
release = [k for k, v in releases.items() if codename in v]
|
||||
ret = (subprocess
|
||||
.check_output(['apt-cache', 'policy', 'swift'])
|
||||
.decode('UTF-8'))
|
||||
if codename in ret or release[0] in ret:
|
||||
return codename
|
||||
elif len(codenames) == 1:
|
||||
@ -441,7 +443,7 @@ def get_swift_codename(version):
|
||||
match = re.match(r'^(\d+)\.(\d+)', version)
|
||||
if match:
|
||||
major_minor_version = match.group(0)
|
||||
for codename, versions in six.iteritems(SWIFT_CODENAMES):
|
||||
for codename, versions in SWIFT_CODENAMES.items():
|
||||
for release_version in versions:
|
||||
if release_version.startswith(major_minor_version):
|
||||
return codename
|
||||
@ -477,9 +479,7 @@ def get_os_codename_package(package, fatal=True):
|
||||
if snap_install_requested():
|
||||
cmd = ['snap', 'list', package]
|
||||
try:
|
||||
out = subprocess.check_output(cmd)
|
||||
if six.PY3:
|
||||
out = out.decode('UTF-8')
|
||||
out = subprocess.check_output(cmd).decode('UTF-8')
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
lines = out.split('\n')
|
||||
@ -549,16 +549,14 @@ def get_os_version_package(pkg, fatal=True):
|
||||
|
||||
if 'swift' in pkg:
|
||||
vers_map = SWIFT_CODENAMES
|
||||
for cname, version in six.iteritems(vers_map):
|
||||
for cname, version in vers_map.items():
|
||||
if cname == codename:
|
||||
return version[-1]
|
||||
else:
|
||||
vers_map = OPENSTACK_CODENAMES
|
||||
for version, cname in six.iteritems(vers_map):
|
||||
for version, cname in vers_map.items():
|
||||
if cname == codename:
|
||||
return version
|
||||
# e = "Could not determine OpenStack version for package: %s" % pkg
|
||||
# error_out(e)
|
||||
|
||||
|
||||
def get_installed_os_version():
|
||||
@ -821,10 +819,10 @@ def save_script_rc(script_path="scripts/scriptrc", **env_vars):
|
||||
if not os.path.exists(os.path.dirname(juju_rc_path)):
|
||||
os.mkdir(os.path.dirname(juju_rc_path))
|
||||
with open(juju_rc_path, 'wt') as rc_script:
|
||||
rc_script.write(
|
||||
"#!/bin/bash\n")
|
||||
[rc_script.write('export %s=%s\n' % (u, p))
|
||||
for u, p in six.iteritems(env_vars) if u != "script_path"]
|
||||
rc_script.write("#!/bin/bash\n")
|
||||
for u, p in env_vars.items():
|
||||
if u != "script_path":
|
||||
rc_script.write('export %s=%s\n' % (u, p))
|
||||
|
||||
|
||||
def openstack_upgrade_available(package):
|
||||
@ -1039,7 +1037,7 @@ def _determine_os_workload_status(
|
||||
state, message, lambda: charm_func(configs))
|
||||
|
||||
if state is None:
|
||||
state, message = _ows_check_services_running(services, ports)
|
||||
state, message = ows_check_services_running(services, ports)
|
||||
|
||||
if state is None:
|
||||
state = 'active'
|
||||
@ -1213,7 +1211,12 @@ def _ows_check_charm_func(state, message, charm_func_with_configs):
|
||||
return state, message |