synced charm-helpers
This commit is contained in:
parent
a2b51aba7a
commit
fc598df4a3
|
@ -1,4 +1,6 @@
|
||||||
import glob
|
import glob
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
@ -172,7 +174,8 @@ def format_ipv6_addr(address):
|
||||||
return address
|
return address
|
||||||
|
|
||||||
|
|
||||||
def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False, fatal=True, exc_list=None):
|
def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False,
|
||||||
|
fatal=True, exc_list=None):
|
||||||
"""
|
"""
|
||||||
Return the assigned IP address for a given interface, if any, or [].
|
Return the assigned IP address for a given interface, if any, or [].
|
||||||
"""
|
"""
|
||||||
|
@ -212,26 +215,67 @@ def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False, fatal=T
|
||||||
if 'addr' in entry and entry['addr'] not in exc_list:
|
if 'addr' in entry and entry['addr'] not in exc_list:
|
||||||
addresses.append(entry['addr'])
|
addresses.append(entry['addr'])
|
||||||
if fatal and not addresses:
|
if fatal and not addresses:
|
||||||
raise Exception("Interface '%s' doesn't have any %s addresses." % (iface, inet_type))
|
raise Exception("Interface '%s' doesn't have any %s addresses." %
|
||||||
|
(iface, inet_type))
|
||||||
return addresses
|
return addresses
|
||||||
|
|
||||||
get_ipv4_addr = partial(get_iface_addr, inet_type='AF_INET')
|
get_ipv4_addr = partial(get_iface_addr, inet_type='AF_INET')
|
||||||
|
|
||||||
|
|
||||||
def get_ipv6_addr(iface='eth0', inc_aliases=False, fatal=True, exc_list=None):
|
def get_ipv6_addr(iface='eth0', inc_aliases=False, fatal=True, exc_list=None,
|
||||||
"""
|
dynamic_only=True):
|
||||||
Return the assigned IPv6 address for a given interface, if any, or [].
|
"""Get assigned IPv6 address for a given interface.
|
||||||
|
|
||||||
|
Returns list of addresses found. If no address found, returns empty list.
|
||||||
|
|
||||||
|
We currently only support scope global IPv6 addresses i.e. non-temporary
|
||||||
|
addresses. If no global IPv6 address is found, return the first one found
|
||||||
|
in the ipv6 address list.
|
||||||
"""
|
"""
|
||||||
addresses = get_iface_addr(iface=iface, inet_type='AF_INET6',
|
addresses = get_iface_addr(iface=iface, inet_type='AF_INET6',
|
||||||
inc_aliases=inc_aliases, fatal=fatal,
|
inc_aliases=inc_aliases, fatal=fatal,
|
||||||
exc_list=exc_list)
|
exc_list=exc_list)
|
||||||
remotly_addressable = []
|
|
||||||
for address in addresses:
|
if addresses:
|
||||||
if not address.startswith('fe80'):
|
global_addrs = []
|
||||||
remotly_addressable.append(address)
|
for addr in addresses:
|
||||||
if fatal and not remotly_addressable:
|
key_scope_link_local = re.compile("^fe80::..(.+)%(.+)")
|
||||||
raise Exception("Interface '%s' doesn't have global ipv6 address." % iface)
|
m = re.match(key_scope_link_local, addr)
|
||||||
return remotly_addressable
|
if m:
|
||||||
|
eui_64_mac = m.group(1)
|
||||||
|
iface = m.group(2)
|
||||||
|
else:
|
||||||
|
global_addrs.append(addr)
|
||||||
|
|
||||||
|
if global_addrs:
|
||||||
|
# Make sure any found global addresses are not temporary
|
||||||
|
cmd = ['ip', 'addr', 'show', iface]
|
||||||
|
out = subprocess.check_output(cmd)
|
||||||
|
if dynamic_only:
|
||||||
|
key = re.compile("inet6 (.+)/[0-9]+ scope global dynamic.*")
|
||||||
|
else:
|
||||||
|
key = re.compile("inet6 (.+)/[0-9]+ scope global.*")
|
||||||
|
|
||||||
|
addrs = []
|
||||||
|
for line in out.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
m = re.match(key, line)
|
||||||
|
if m and 'temporary' not in line:
|
||||||
|
# Return the first valid address we find
|
||||||
|
for addr in global_addrs:
|
||||||
|
if m.group(1) == addr:
|
||||||
|
if not dynamic_only or \
|
||||||
|
m.group(1).endswith(eui_64_mac):
|
||||||
|
addrs.append(addr)
|
||||||
|
|
||||||
|
if addrs:
|
||||||
|
return addrs
|
||||||
|
|
||||||
|
if fatal:
|
||||||
|
raise Exception("Interface '%s' doesn't have a scope global "
|
||||||
|
"non-temporary ipv6 address." % iface)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_bridges(vnic_dir='/sys/devices/virtual/net'):
|
def get_bridges(vnic_dir='/sys/devices/virtual/net'):
|
||||||
|
|
|
@ -486,9 +486,10 @@ class Hooks(object):
|
||||||
hooks.execute(sys.argv)
|
hooks.execute(sys.argv)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, config_save=True):
|
||||||
super(Hooks, self).__init__()
|
super(Hooks, self).__init__()
|
||||||
self._hooks = {}
|
self._hooks = {}
|
||||||
|
self._config_save = config_save
|
||||||
|
|
||||||
def register(self, name, function):
|
def register(self, name, function):
|
||||||
"""Register a hook"""
|
"""Register a hook"""
|
||||||
|
@ -499,9 +500,10 @@ class Hooks(object):
|
||||||
hook_name = os.path.basename(args[0])
|
hook_name = os.path.basename(args[0])
|
||||||
if hook_name in self._hooks:
|
if hook_name in self._hooks:
|
||||||
self._hooks[hook_name]()
|
self._hooks[hook_name]()
|
||||||
cfg = config()
|
if self._config_save:
|
||||||
if cfg.implicit_save:
|
cfg = config()
|
||||||
cfg.save()
|
if cfg.implicit_save:
|
||||||
|
cfg.save()
|
||||||
else:
|
else:
|
||||||
raise UnregisteredHookError(hook_name)
|
raise UnregisteredHookError(hook_name)
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,8 @@ def service_available(service_name):
|
||||||
"""Determine whether a system service is available"""
|
"""Determine whether a system service is available"""
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(['service', service_name, 'status'], stderr=subprocess.STDOUT)
|
subprocess.check_output(['service', service_name, 'status'], stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError as e:
|
||||||
return False
|
return 'unrecognized service' not in e.output
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -229,12 +229,12 @@ def check_hash(path, checksum, hash_type='md5'):
|
||||||
"""
|
"""
|
||||||
Validate a file using a cryptographic checksum.
|
Validate a file using a cryptographic checksum.
|
||||||
|
|
||||||
|
|
||||||
:param str checksum: Value of the checksum used to validate the file.
|
:param str checksum: Value of the checksum used to validate the file.
|
||||||
:param str hash_type: Hash algorithm used to generate :param:`checksum`.
|
:param str hash_type: Hash algorithm used to generate `checksum`.
|
||||||
Can be any hash alrgorithm supported by :mod:`hashlib`,
|
Can be any hash alrgorithm supported by :mod:`hashlib`,
|
||||||
such as md5, sha1, sha256, sha512, etc.
|
such as md5, sha1, sha256, sha512, etc.
|
||||||
:raises ChecksumError: If the file fails the checksum
|
:raises ChecksumError: If the file fails the checksum
|
||||||
|
|
||||||
"""
|
"""
|
||||||
actual_checksum = file_hash(path, hash_type)
|
actual_checksum = file_hash(path, hash_type)
|
||||||
if checksum != actual_checksum:
|
if checksum != actual_checksum:
|
||||||
|
|
|
@ -208,7 +208,8 @@ def add_source(source, key=None):
|
||||||
"""Add a package source to this system.
|
"""Add a package source to this system.
|
||||||
|
|
||||||
@param source: a URL or sources.list entry, as supported by
|
@param source: a URL or sources.list entry, as supported by
|
||||||
add-apt-repository(1). Examples:
|
add-apt-repository(1). Examples::
|
||||||
|
|
||||||
ppa:charmers/example
|
ppa:charmers/example
|
||||||
deb https://stub:key@private.example.com/ubuntu trusty main
|
deb https://stub:key@private.example.com/ubuntu trusty main
|
||||||
|
|
||||||
|
|
|
@ -74,18 +74,19 @@ class ArchiveUrlFetchHandler(BaseFetchHandler):
|
||||||
"""
|
"""
|
||||||
Download and install an archive file, with optional checksum validation.
|
Download and install an archive file, with optional checksum validation.
|
||||||
|
|
||||||
The checksum can also be given on the :param:`source` URL's fragment.
|
The checksum can also be given on the `source` URL's fragment.
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
handler.install('http://example.com/file.tgz#sha1=deadbeef')
|
handler.install('http://example.com/file.tgz#sha1=deadbeef')
|
||||||
|
|
||||||
:param str source: URL pointing to an archive file.
|
:param str source: URL pointing to an archive file.
|
||||||
:param str dest: Local destination path to install to. If not given,
|
:param str dest: Local destination path to install to. If not given,
|
||||||
installs to `$CHARM_DIR/archives/archive_file_name`.
|
installs to `$CHARM_DIR/archives/archive_file_name`.
|
||||||
:param str checksum: If given, validate the archive file after download.
|
:param str checksum: If given, validate the archive file after download.
|
||||||
:param str hash_type: Algorithm used to generate :param:`checksum`.
|
:param str hash_type: Algorithm used to generate `checksum`.
|
||||||
Can be any hash alrgorithm supported by :mod:`hashlib`,
|
Can be any hash alrgorithm supported by :mod:`hashlib`,
|
||||||
such as md5, sha1, sha256, sha512, etc.
|
such as md5, sha1, sha256, sha512, etc.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
url_parts = self.parse_url(source)
|
url_parts = self.parse_url(source)
|
||||||
dest_dir = os.path.join(os.environ.get('CHARM_DIR'), 'fetched')
|
dest_dir = os.path.join(os.environ.get('CHARM_DIR'), 'fetched')
|
||||||
|
|
Loading…
Reference in New Issue