PSARC/2014/207 OpenStack Glance Update to Havana
PSARC/2014/208 OpenStack Cinder Update to Havana
PSARC/2014/209 OpenStack Keystone Update to Havana
PSARC/2014/210 OpenStack Nova Update to Havana
18416146 Neutron agents (L3 and DHCP) should cleanup resources when they are disabled
18562372 Failed to create a new project under Horizon
18645763 ZFSSA Cinder Driver support
18686327 evs agent silently ignores user-specified pool allocation ranges
18702697 fibre channel volumes should be supported in the cinder volume driver
18734289 nova won't terminate failed kz deployments
18738371 cinder-volume:setup should account for commented-out zfs_volume_base
18738374 cinder-volume:setup should check for existence of configuration file
18826190 nova-compute fails due to nova.utils.to_bytes
18855698 Update OpenStack to Havana 2013.2.3
18855710 Update python-cinderclient to 1.0.9
18855743 Update python-keystoneclient to 0.8.0
18855754 Update python-neutronclient to 2.3.4
18855764 Update python-novaclient to 2.17.0
18855793 Update python-swiftclient to 2.1.0
18856992 External networks can be deleted even when floating IP addresses are in use
18857784 bake in some more openstack configuration
18884923 Incorrect locale facets in python modules for openstack
18913890 the error in _get_view_and_lun may cause the failure of deleting volumes
18943044 Disable 'Security Groups' tab in Horizon dashboard
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
#
# 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.
#
# @author: Girish Moodalbail, Oracle, Inc.
#
import netaddr
from neutron.agent.linux import utils
class CommandBase(object):
@classmethod
def execute_with_pfexec(cls, cmd, **kwargs):
# uses pfexec
cmd.insert(0, '/usr/bin/pfexec')
return utils.execute(cmd, **kwargs)
@classmethod
def execute(cls, cmd, **kwargs):
return utils.execute(cmd, **kwargs)
class IPInterface(CommandBase):
'''Wrapper around Solaris ipadm(1m) command.'''
def __init__(self, ifname):
self._ifname = ifname
@classmethod
def ifname_exists(cls, ifname):
cmd = ['/usr/sbin/ipadm', 'show-if', '-po', 'ifname']
stdout = cls.execute(cmd)
return ifname in stdout
@classmethod
def ipaddr_exists(cls, ifname, ipaddr):
if not cls.ifname_exists(ifname):
return False
cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'addr', ifname]
stdout = cls.execute(cmd)
return ipaddr in stdout
def ipaddr_list(self, filters=None):
cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'type,addr',
self._ifname]
stdout = self.execute(cmd)
atype_addrs = stdout.strip().split('\n')
result = {}
for atype_addr in atype_addrs:
atype, addr = atype_addr.split(':', 1)
val = result.get(atype)
if val is None:
result[atype] = []
val = result.get(atype)
# in the case of IPv6 addresses remove any escape '\' character
val.append(addr.replace("\\", ""))
return result
def create_address(self, ipaddr, addrobjname=None, temp=True):
if not self.ifname_exists(self._ifname):
# create ip interface
cmd = ['/usr/sbin/ipadm', 'create-ip', self._ifname]
if temp:
cmd.append('-t')
self.execute_with_pfexec(cmd)
if self.ipaddr_exists(self._ifname, ipaddr):
return
# If an address is IPv6, then to create a static IPv6 address
# we need to create link-local address first
if netaddr.IPNetwork(ipaddr).version == 6:
# check if link-local address already exists
cmd = ['/usr/sbin/dladm', 'show-linkprop', '-co', 'value',
'-p', 'mac-address', self._ifname]
stdout = self.execute(cmd)
mac_addr = stdout.splitlines()[0].strip()
ll_addr = netaddr.EUI(mac_addr).ipv6_link_local()
if not self.ipaddr_exists(self._ifname, str(ll_addr)):
# create a link-local address
cmd = ['/usr/sbin/ipadm', 'create-addr', '-T', 'static', '-a',
str(ll_addr), self._ifname]
if temp:
cmd.append('-t')
self.execute_with_pfexec(cmd)
cmd = ['/usr/sbin/ipadm', 'create-addr', '-T', 'static', '-a',
ipaddr, self._ifname]
if temp:
cmd.append('-t')
return self.execute_with_pfexec(cmd)
def delete_address(self, ipaddr):
if not self.ipaddr_exists(self._ifname, ipaddr):
return
cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'addrobj,addr',
self._ifname]
stdout = self.execute(cmd)
aobj_addrs = stdout.strip().split('\n')
for aobj_addr in aobj_addrs:
if ipaddr not in aobj_addr:
continue
aobj = aobj_addr.split(':')[0]
cmd = ['/usr/sbin/ipadm', 'delete-addr', aobj]
self.execute_with_pfexec(cmd)
break
isV6 = netaddr.IPNetwork(ipaddr).version == 6
if len(aobj_addrs) == 1 or (isV6 and len(aobj_addrs) == 2):
# delete the interface as well
cmd = ['/usr/sbin/ipadm', 'delete-ip', self._ifname]
self.execute_with_pfexec(cmd)
def delete_ip(self):
if not self.ifname_exists(self._ifname):
return
cmd = ['/usr/sbin/ipadm', 'delete-ip', self._ifname]
self.execute_with_pfexec(cmd)
class Datalink(CommandBase):
'''Wrapper around Solaris dladm(1m) command.'''
def __init__(self, dlname):
self._dlname = dlname
@classmethod
def datalink_exists(cls, dlname):
cmd = ['/usr/sbin/dladm', 'show-link', '-po', 'link']
stdout = utils.execute(cmd)
return dlname in stdout
def connect_vnic(self, evsvport, tenantname=None, temp=True):
if self.datalink_exists(self._dlname):
return
cmd = ['/usr/sbin/dladm', 'create-vnic', '-c', evsvport, self._dlname]
if temp:
cmd.append('-t')
if tenantname:
cmd.append('-T')
cmd.append(tenantname)
return self.execute_with_pfexec(cmd)
def create_vnic(self, lower_link, mac_address=None, vid=None, temp=True):
if self.datalink_exists(self._dlname):
return
if vid:
# If the default_tag of lower_link is same as vid, then there
# is no need to set vid
cmd = ['/usr/sbin/dladm', 'show-linkprop', '-co', 'value',
'-p', 'default_tag', lower_link]
stdout = utils.execute(cmd)
if stdout.splitlines()[0].strip() == vid:
vid = '0'
else:
vid = '0'
cmd = ['/usr/sbin/dladm', 'create-vnic', '-l', lower_link,
'-m', mac_address, '-v', vid, self._dlname]
if temp:
cmd.append('-t')
return self.execute_with_pfexec(cmd)
def delete_vnic(self):
if not self.datalink_exists(self._dlname):
return
cmd = ['/usr/sbin/dladm', 'delete-vnic', self._dlname]
return self.execute_with_pfexec(cmd)
class IPpoolCommand(CommandBase):
'''Wrapper around Solaris ippool(1m) command'''
def __init__(self, pool_name, role='ipf', pool_type='tree'):
self._pool_name = pool_name
self._role = role
self._pool_type = pool_type
def pool_exists(self):
cmd = ['/usr/sbin/ippool', '-l', '-m', self._pool_name,
'-t', self._pool_type]
stdout = self.execute_with_pfexec(cmd)
return str(self._pool_name) in stdout
def pool_split_nodes(self, ip_cidrs):
cmd = ['/usr/sbin/ippool', '-l', '-m', self._pool_name,
'-t', self._pool_type]
stdout = self.execute_with_pfexec(cmd)
existing_nodes = []
non_existing_nodes = []
for ip_cidr in ip_cidrs:
if ip_cidr in stdout:
existing_nodes.append(ip_cidr)
else:
non_existing_nodes.append(ip_cidr)
return existing_nodes, non_existing_nodes
def add_pool_nodes(self, ip_cidrs):
ip_cidrs = self.pool_split_nodes(ip_cidrs)[1]
for ip_cidr in ip_cidrs:
cmd = ['/usr/sbin/ippool', '-a', '-m', self._pool_name,
'-i', ip_cidr]
self.execute_with_pfexec(cmd)
def remove_pool_nodes(self, ip_cidrs):
ip_cidrs = self.pool_split_nodes(ip_cidrs)[0]
for ip_cidr in ip_cidrs:
cmd = ['/usr/sbin/ippool', '-r', '-m', self._pool_name,
'-i', ip_cidr]
self.execute_with_pfexec(cmd)
def add_pool(self):
if self.pool_exists():
return
cmd = ['/usr/sbin/ippool', '-A', '-m', self._pool_name,
'-o', self._role, '-t', self._pool_type]
self.execute_with_pfexec(cmd)
def remove_pool(self):
if not self.pool_exists():
return
# This command will fail if ippool is in use by ipf, so the
# caller has to ensure that it's not being used in an ipf rule
cmd = ['/usr/sbin/ippool', '-R', '-m', self._pool_name,
'-o', self._role, '-t', self._pool_type]
self.execute_with_pfexec(cmd)
class IPfilterCommand(CommandBase):
'''Wrapper around Solaris ipf(1m) command'''
def split_rules(self, rules):
# assumes that rules are inbound!
cmd = ['/usr/sbin/ipfstat', '-i']
stdout = self.execute_with_pfexec(cmd)
existing_rules = []
non_existing_rules = []
for rule in rules:
if rule in stdout:
existing_rules.append(rule)
else:
non_existing_rules.append(rule)
return existing_rules, non_existing_rules
def add_rules(self, rules, version='4'):
rules = self.split_rules(rules)[1]
process_input = '\n'.join(rules)
cmd = ['/usr/sbin/ipf', '-f', '-']
if version == '6':
cmd.append('-6')
return self.execute_with_pfexec(cmd, process_input=process_input)
def remove_rules(self, rules, version='4'):
rules = self.split_rules(rules)[0]
process_input = '\n'.join(rules)
cmd = ['/usr/sbin/ipf', '-r', '-f', '-']
if version == '6':
cmd.append('-6')
return self.execute_with_pfexec(cmd, process_input=process_input)
class IPnatCommand(CommandBase):
'''Wrapper around Solaris ipnat(1m) command'''
def add_rules(self, rules):
process_input = '\n'.join(rules)
cmd = ['/usr/sbin/ipnat', '-f', '-']
return self.execute_with_pfexec(cmd, process_input=process_input)
def remove_rules(self, rules):
process_input = '\n'.join(rules)
cmd = ['/usr/sbin/ipnat', '-r', '-f', '-']
return self.execute_with_pfexec(cmd, process_input=process_input)