diff options
author | novel <novel@FreeBSD.org> | 2016-12-18 14:30:58 +0800 |
---|---|---|
committer | novel <novel@FreeBSD.org> | 2016-12-18 14:30:58 +0800 |
commit | 5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4 (patch) | |
tree | 55bfb76270b1d02dea6f42d78e0c7b0c20fe637d /emulators/py-nova | |
parent | b7437dc88ef9ee693e676aa457b38aa98cff2a45 (diff) | |
download | freebsd-ports-gnome-5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4.tar.gz freebsd-ports-gnome-5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4.tar.zst freebsd-ports-gnome-5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4.zip |
Add emulators/py-nova 14.0.2, Openstack Compute Service
Please note that this is a development version of nova.
Many features are not available.
Currently nova works on FreeBSD 11 and supports QEMU and Xen.
Common issues:
- Security groups are not implemented
- ARP spoofing, DHCP isolation protection are not implemented
- Nova services work from the root user
- No IPv6 support
QEMU issues:
- Need to enable serialconsole (TCP)
- Need to disable online CPU tracking
- Cannot mount cinder volumes
Xen issues:
- Live snapshots don't work
- No support for cinder volume hot-plugging
- XENBUS delay (5 min) when using qemu driver and COW images
- Some Linux images cannot be booted
For further FreeBSD specific notes please refer to port's pkg-message.
PR: 215151
Submitted by: Alexander Nusov (alexander.nusov@nfvexpress.com)
Diffstat (limited to 'emulators/py-nova')
22 files changed, 2337 insertions, 0 deletions
diff --git a/emulators/py-nova/Makefile b/emulators/py-nova/Makefile new file mode 100644 index 000000000000..bf8db9b6e010 --- /dev/null +++ b/emulators/py-nova/Makefile @@ -0,0 +1,141 @@ +# Created by: Alexander Nusov <alexander.nusov@nfvexpress.com> +# $FreeBSD$ + +PORTNAME= nova +PORTVERSION= 14.0.2 +CATEGORIES= emulators python +MASTER_SITES= https://fossies.org/linux/misc/openstack/ +PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX} + +MAINTAINER= alexander.nusov@nfvexpress.com +COMMENT= OpenStack compute service + +LICENSE= APACHE20 + +BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}pbr>=1.6:devel/py-pbr + +RUN_DEPENDS:= ${BUILD_DEPENDS} +RUN_DEPENDS+= ${PYTHON_PKGNAMEPREFIX}sqlalchemy10>=0:databases/py-sqlalchemy10 \ + ${PYTHON_PKGNAMEPREFIX}boto>=2.32.1:devel/py-boto \ + ${PYTHON_PKGNAMEPREFIX}decorator>=3.4.0:devel/py-decorator \ + ${PYTHON_PKGNAMEPREFIX}eventlet>=0:net/py-eventlet \ + ${PYTHON_PKGNAMEPREFIX}Jinja2>=2.8:devel/py-Jinja2 \ + ${PYTHON_PKGNAMEPREFIX}keystonemiddleware>=0:devel/py-keystonemiddleware \ + ${PYTHON_PKGNAMEPREFIX}lxml>=2.3:devel/py-lxml \ + ${PYTHON_PKGNAMEPREFIX}routes>=0:www/py-routes \ + ${PYTHON_PKGNAMEPREFIX}cryptography>=0:security/py-cryptography \ + ${PYTHON_PKGNAMEPREFIX}webob>=1.2.3:www/py-webob \ + ${PYTHON_PKGNAMEPREFIX}greenlet>=0.3.2:devel/py-greenlet \ + ${PYTHON_PKGNAMEPREFIX}PasteDeploy>=1.5.0:www/py-pastedeploy \ + ${PYTHON_PKGNAMEPREFIX}Paste>=0:www/py-paste \ + ${PYTHON_PKGNAMEPREFIX}prettytable>=0:devel/py-prettytable \ + ${PYTHON_PKGNAMEPREFIX}sqlalchemy-migrate>=0.9.6:databases/py-sqlalchemy-migrate \ + ${PYTHON_PKGNAMEPREFIX}netaddr>=0:net/py-netaddr \ + ${PYTHON_PKGNAMEPREFIX}netifaces>=0.10.4:net/py-netifaces \ + ${PYTHON_PKGNAMEPREFIX}paramiko>=2.0:security/py-paramiko \ + ${PYTHON_PKGNAMEPREFIX}Babel>=2.3.4:devel/py-babel \ + ${PYTHON_PKGNAMEPREFIX}iso8601>=0.1.11:devel/py-iso8601 \ + ${PYTHON_PKGNAMEPREFIX}jsonschema>=0:devel/py-jsonschema \ + ${PYTHON_PKGNAMEPREFIX}python-cinderclient>=0:net/py-python-cinderclient \ + ${PYTHON_PKGNAMEPREFIX}keystoneauth1>=2.10.0:devel/py-keystoneauth1 \ + ${PYTHON_PKGNAMEPREFIX}python-neutronclient>=5.1.0:net/py-python-neutronclient \ + ${PYTHON_PKGNAMEPREFIX}python-glanceclient>=0:net/py-python-glanceclient \ + ${PYTHON_PKGNAMEPREFIX}requests>=2.10.0:www/py-requests \ + ${PYTHON_PKGNAMEPREFIX}six>=1.9.0:devel/py-six \ + ${PYTHON_PKGNAMEPREFIX}stevedore>=1.16.0:devel/py-stevedore \ + ${PYTHON_PKGNAMEPREFIX}websockify>=0.8.0:devel/py-websockify \ + ${PYTHON_PKGNAMEPREFIX}oslo.cache>=1.5.0:devel/py-oslo.cache \ + ${PYTHON_PKGNAMEPREFIX}oslo.concurrency>=3.8.0:devel/py-oslo.concurrency \ + ${PYTHON_PKGNAMEPREFIX}oslo.config>=3.14.0:devel/py-oslo.config \ + ${PYTHON_PKGNAMEPREFIX}oslo.context>=2.9.0:devel/py-oslo.context \ + ${PYTHON_PKGNAMEPREFIX}oslo.log>=1.14.0:devel/py-oslo.log \ + ${PYTHON_PKGNAMEPREFIX}oslo.reports>=0.6.0:devel/py-oslo.reports \ + ${PYTHON_PKGNAMEPREFIX}oslo.serialization>=1.10.0:devel/py-oslo.serialization \ + ${PYTHON_PKGNAMEPREFIX}oslo.utils>=3.16.0:devel/py-oslo.utils \ + ${PYTHON_PKGNAMEPREFIX}oslo.db>=0:devel/py-oslo.db \ + ${PYTHON_PKGNAMEPREFIX}oslo.rootwrap>=5.0.0:devel/py-oslo.rootwrap \ + ${PYTHON_PKGNAMEPREFIX}oslo.messaging>=5.2.0:devel/py-oslo.messaging \ + ${PYTHON_PKGNAMEPREFIX}oslo.policy>=1.9.0:devel/py-oslo.policy \ + ${PYTHON_PKGNAMEPREFIX}oslo.privsep>=1.9.0:devel/py-oslo.privsep \ + ${PYTHON_PKGNAMEPREFIX}oslo.i18n>=2.1.0:devel/py-oslo.i18n \ + ${PYTHON_PKGNAMEPREFIX}oslo.service>=1.10.0:devel/py-oslo.service \ + ${PYTHON_PKGNAMEPREFIX}rfc3986>=0.2.2:www/py-rfc3986 \ + ${PYTHON_PKGNAMEPREFIX}oslo.middleware>=3.0.0:devel/py-oslo.middleware \ + ${PYTHON_PKGNAMEPREFIX}psutil121>=0:sysutils/py-psutil121 \ + ${PYTHON_PKGNAMEPREFIX}oslo.versionedobjects>=1.13.0:devel/py-oslo.versionedobjects \ + ${PYTHON_PKGNAMEPREFIX}os-brick>=1.6.1:devel/py-os-brick \ + ${PYTHON_PKGNAMEPREFIX}os-vif>=1.1.0:devel/py-os-vif \ + ${PYTHON_PKGNAMEPREFIX}os-win>=0.2.3:devel/py-os-win \ + ${PYTHON_PKGNAMEPREFIX}castellan>=0.4.0:devel/py-castellan \ + ${PYTHON_PKGNAMEPREFIX}microversion-parse>=0.1.2:devel/py-microversion-parse \ + ${PYTHON_PKGNAMEPREFIX}wsgi_intercept>=0.6.1:devel/py-wsgi_intercept \ + ${PYTHON_PKGNAMEPREFIX}sqlparse>=0:databases/py-sqlparse \ + ${PYTHON_PKGNAMEPREFIX}libvirt>=0:devel/py-libvirt \ + e2fsprogs>=0:sysutils/e2fsprogs \ + arping>=0:net/arping + +EXTRA_PATCHES= ${FILESDIR}/01-firewall-manager.patch:-p1 \ + ${FILESDIR}/02-freebsd-l3.patch:-p1 \ + ${FILESDIR}/03-nova-conf.patch:-p1 \ + ${FILESDIR}/04-xen-phy.patch:-p1 \ + ${FILESDIR}/05-online-cpus.patch:-p1 \ + ${FILESDIR}/06-freebsd-net.patch:-p1 + +ONLY_FOR_ARCHS= amd64 + +USES= python +USE_PYTHON= autoplist distutils noegginfo + +USE_RC_SUBR= nova-api \ + nova-consoleauth \ + nova-conductor \ + nova-scheduler \ + nova-network \ + nova-compute \ + nova-cert \ + nova-cells \ + nova-serialproxy +USERS= nova +GROUPS= nova + +.include <bsd.port.options.mk> + +.if ${OPSYS} != FreeBSD +IGNORE= only supported on FreeBSD +.endif + +.if ${OSVERSION} < 1100055 +IGNORE= only supported on recent FreeBSD 11 +.endif + +post-extract: + @(cd ${WRKSRC}/etc/nova; ${MV} logging_sample.conf logging.conf.sample) + @(cd ${WRKSRC}/etc/nova; for f in *.conf; do ${MV} $${f} $${f}.sample; done) + +post-patch: + ${CP} ${FILESDIR}/nova.conf.sample \ + ${WRKSRC}/etc/nova/nova.conf.sample + ${CP} ${FILESDIR}/nova-compute.conf.sample \ + ${WRKSRC}/etc/nova/nova-compute.conf.sample + ${REINPLACE_CMD} -e "s|/etc|${PREFIX}/etc|g" \ + ${WRKSRC}/nova/api/openstack/placement/wsgi.py \ + ${WRKSRC}/nova/conf/base.py \ + ${WRKSRC}/nova/conf/cloudpipe.py \ + ${WRKSRC}/nova/conf/network.py \ + ${WRKSRC}/nova/conf/remote_debug.py \ + ${WRKSRC}/nova/conf/xvp.py \ + ${WRKSRC}/nova/hacking/checks.py \ + ${WRKSRC}/nova/network/linux_net.py \ + ${WRKSRC}/nova/network/manager.py \ + ${WRKSRC}/nova/virt/disk/api.py \ + ${WRKSRC}/nova/virt/disk/vfs/guestfs.py \ + ${WRKSRC}/nova/virt/libvirt/driver.py \ + ${WRKSRC}/nova/virt/xenapi/agent.py \ + ${WRKSRC}/nova/wsgi/nova-api.py \ + ${WRKSRC}/nova/wsgi/nova-metadata.py + +post-install: + ${MKDIR} ${STAGEDIR}${ETCDIR} + ${CP} -R ${WRKSRC}/etc/nova/ ${STAGEDIR}${ETCDIR} + +.include <bsd.port.mk> diff --git a/emulators/py-nova/distinfo b/emulators/py-nova/distinfo new file mode 100644 index 000000000000..584c6e6b86c7 --- /dev/null +++ b/emulators/py-nova/distinfo @@ -0,0 +1,3 @@ +TIMESTAMP = 1478994869 +SHA256 (nova-14.0.2.tar.gz) = e98291734b4b16615fb1518161c89749f09ad33b6344feb70d62b69e8161a50d +SIZE (nova-14.0.2.tar.gz) = 5574197 diff --git a/emulators/py-nova/files/01-firewall-manager.patch b/emulators/py-nova/files/01-firewall-manager.patch new file mode 100644 index 000000000000..6af08d977c4d --- /dev/null +++ b/emulators/py-nova/files/01-firewall-manager.patch @@ -0,0 +1,60 @@ +From 60668a502b5f7af77861507e94a89b7f4201c2cb Mon Sep 17 00:00:00 2001 +From: Alexander Nusov <alexander.nusov@nfvexpress.com> +Date: Tue, 8 Nov 2016 16:52:29 +0300 +Subject: [PATCH] add get_firewall_manager + +--- + nova/network/linux_net.py | 4 ++++ + nova/network/manager.py | 8 ++++---- + 2 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py +index b10fa28..2637e26 100644 +--- a/nova/network/linux_net.py ++++ b/nova/network/linux_net.py +@@ -1898,3 +1898,7 @@ def set_vf_interface_vlan(pci_addr, mac_addr, vlan=0): + port_state, + run_as_root=True, + check_exit_code=exit_code) ++ ++ ++def get_firewall_manager(): ++ return iptables_manager +diff --git a/nova/network/manager.py b/nova/network/manager.py +index 9de53d9..f6eb106 100644 +--- a/nova/network/manager.py ++++ b/nova/network/manager.py +@@ -1799,13 +1799,13 @@ class FlatDHCPManager(RPCAllocateFixedIP, floating_ips.FloatingIP, + ctxt = context.get_admin_context() + networks = objects.NetworkList.get_by_host(ctxt, self.host) + +- self.driver.iptables_manager.defer_apply_on() ++ self.driver.get_firewall_manager().defer_apply_on() + + self.l3driver.initialize(fixed_range=False, networks=networks) + super(FlatDHCPManager, self).init_host() + self.init_host_floating_ips() + +- self.driver.iptables_manager.defer_apply_off() ++ self.driver.get_firewall_manager().defer_apply_off() + + def _setup_network_on_host(self, context, network): + """Sets up network on this host.""" +@@ -1887,13 +1887,13 @@ class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager): + ctxt = context.get_admin_context() + networks = objects.NetworkList.get_by_host(ctxt, self.host) + +- self.driver.iptables_manager.defer_apply_on() ++ self.driver.get_firewall_manager().defer_apply_on() + + self.l3driver.initialize(fixed_range=False, networks=networks) + NetworkManager.init_host(self) + self.init_host_floating_ips() + +- self.driver.iptables_manager.defer_apply_off() ++ self.driver.get_firewall_manager().defer_apply_off() + + def allocate_fixed_ip(self, context, instance_id, network, **kwargs): + """Gets a fixed IP from the pool.""" +-- +2.8.1 diff --git a/emulators/py-nova/files/02-freebsd-l3.patch b/emulators/py-nova/files/02-freebsd-l3.patch new file mode 100644 index 000000000000..61677b3b6aed --- /dev/null +++ b/emulators/py-nova/files/02-freebsd-l3.patch @@ -0,0 +1,90 @@ +From 2e4a0e0a2588c4d52495fad8105aa1a4609797f6 Mon Sep 17 00:00:00 2001 +From: Alexander Nusov <alexander.nusov@nfvexpress.com> +Date: Tue, 8 Nov 2016 16:50:56 +0300 +Subject: [PATCH] add freebsd l3 driver + +--- + nova/network/l3.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +diff --git a/nova/network/l3.py b/nova/network/l3.py +index c13e6e2..a5982d5 100644 +--- a/nova/network/l3.py ++++ b/nova/network/l3.py +@@ -16,6 +16,7 @@ + from oslo_log import log as logging + + from nova.network import linux_net ++from nova.network import freebsd_net + from nova import utils + + LOG = logging.getLogger(__name__) +@@ -134,6 +135,66 @@ class LinuxNetL3(L3Driver): + pass + + ++class FreeBSDNetL3(L3Driver): ++ """L3 driver that uses freebsd_net as the backend.""" ++ def __init__(self): ++ self.initialized = False ++ ++ def initialize(self, **kwargs): ++ if self.initialized: ++ return ++ LOG.debug("Initializing freebsd_net L3 driver") ++ fixed_range = kwargs.get('fixed_range', False) ++ networks = kwargs.get('networks', None) ++ if not fixed_range and networks is not None: ++ for network in networks: ++ if network['enable_dhcp']: ++ is_ext = (network['dhcp_server'] is not None and ++ network['dhcp_server'] != network['gateway']) ++ self.initialize_network(network['cidr'], is_ext) ++ freebsd_net.ensure_metadata_ip() ++ freebsd_net.metadata_forward() ++ self.initialized = True ++ ++ def is_initialized(self): ++ return self.initialized ++ ++ def initialize_network(self, cidr, is_external): ++ freebsd_net.init_host(cidr, is_external) ++ ++ def initialize_gateway(self, network_ref): ++ mac_address = utils.generate_mac_address() ++ dev = freebsd_net.plug(network_ref, mac_address, ++ gateway=(network_ref['gateway'] is not None)) ++ freebsd_net.initialize_gateway_device(dev, network_ref) ++ ++ def remove_gateway(self, network_ref): ++ freebsd_net.unplug(network_ref) ++ ++ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id, ++ network=None): ++ freebsd_net.ensure_floating_forward(floating_ip, fixed_ip, ++ l3_interface_id, network) ++ freebsd_net.bind_floating_ip(floating_ip, l3_interface_id) ++ ++ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id, ++ network=None): ++ freebsd_net.unbind_floating_ip(floating_ip, l3_interface_id) ++ freebsd_net.remove_floating_forward(floating_ip, fixed_ip, ++ l3_interface_id, network) ++ freebsd_net.clean_conntrack(fixed_ip) ++ ++ def add_vpn(self, public_ip, port, private_ip): ++ freebsd_net.ensure_vpn_forward(public_ip, port, private_ip) ++ ++ def remove_vpn(self, public_ip, port, private_ip): ++ # FreeBSD net currently doesn't implement any way of removing ++ # the VPN forwarding rules ++ pass ++ ++ def teardown(self): ++ pass ++ + class NullL3(L3Driver): + """The L3 driver that doesn't do anything. This class can be used when + nova-network should not manipulate L3 forwarding at all (e.g., in a Flat +-- +2.8.1 diff --git a/emulators/py-nova/files/03-nova-conf.patch b/emulators/py-nova/files/03-nova-conf.patch new file mode 100644 index 000000000000..8aa0edb08c87 --- /dev/null +++ b/emulators/py-nova/files/03-nova-conf.patch @@ -0,0 +1,51 @@ +diff --git a/nova/conf/network.py b/nova/conf/network.py +index 3bb4cd9..eb57041 100644 +--- a/nova/conf/network.py ++++ b/nova/conf/network.py +@@ -704,6 +704,30 @@ Related options: + """), + ] + ++freebsd_net_opts = [ ++ cfg.StrOpt("freebsdnet_interface_driver", ++ default="nova.network.freebsd.FreeBSDBridgeInterfaceDriver", ++ help=""" ++This is the class used as the ethernet device driver for freebsdnet bridge ++operations. The default value should be all you need for most cases, but if you ++wish to use a customized class, set this option to the full dot-separated ++import path for that class. ++ ++Possible values: ++ ++ Any string representing a dot-separated class path that Nova can import. ++"""), ++ cfg.StrOpt("freebsdnet_ovs_integration_bridge", ++ default="br-int", ++ help=""" ++The name of the Open vSwitch bridge that is used with freebsdnet when connecting ++with Open vSwitch." ++ ++Possible values: ++ ++ Any string representing a valid bridge name. ++"""), ++] + + ldap_dns_opts = [ + cfg.StrOpt('ldap_dns_url', +@@ -766,12 +790,13 @@ by using this option. + 'some rpc network calls will be sent directly to host.'), + ] + +-ALL_DEFAULT_OPTS = (linux_net_opts + network_opts + ldap_dns_opts ++ALL_DEFAULT_OPTS = (linux_net_opts + freebsd_net_opts + network_opts + ldap_dns_opts + + rpcapi_opts + driver_opts) + + + def register_opts(conf): + conf.register_opts(linux_net_opts) ++ conf.register_opts(freebsd_net_opts) + conf.register_opts(network_opts) + conf.register_opts(ldap_dns_opts) + conf.register_opts(driver_opts) + diff --git a/emulators/py-nova/files/04-xen-phy.patch b/emulators/py-nova/files/04-xen-phy.patch new file mode 100644 index 000000000000..84b4a07975c9 --- /dev/null +++ b/emulators/py-nova/files/04-xen-phy.patch @@ -0,0 +1,42 @@ +From b4e9024ac90ed0eaf155bc24ef7ee3b01112366e Mon Sep 17 00:00:00 2001 +From: Alexander Nusov <alexander.nusov@nfvexpress.com> +Date: Tue, 15 Nov 2016 13:08:49 +0300 +Subject: [PATCH] foce xen phy option + +--- + nova/conf/libvirt.py | 3 +++ + nova/virt/libvirt/utils.py | 2 +- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py +index bfb278e..2eba080 100644 +--- a/nova/conf/libvirt.py ++++ b/nova/conf/libvirt.py +@@ -498,6 +498,9 @@ libvirt_imagebackend_opts = [ + help='Discard option for nova managed disks. Need' + ' Libvirt(1.0.6) Qemu1.5 (raw format) Qemu1.6(qcow2' + ' format)'), ++ cfg.BoolOpt('force_xen_phy', ++ default=False, ++ help='Force using of PHY driver in Xen'), + ] + + libvirt_imagecache_opts = [ +diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py +index f0a4796..ff68d45 100644 +--- a/nova/virt/libvirt/utils.py ++++ b/nova/virt/libvirt/utils.py +@@ -112,7 +112,7 @@ def pick_disk_driver_name(hypervisor_version, is_block_dev=False): + :returns: driver_name or None + """ + if CONF.libvirt.virt_type == "xen": +- if is_block_dev: ++ if is_block_dev or CONF.libvirt.force_xen_phy: + return "phy" + else: + # 4002000 == 4.2.0 +-- +2.8.1 + + + diff --git a/emulators/py-nova/files/05-online-cpus.patch b/emulators/py-nova/files/05-online-cpus.patch new file mode 100644 index 000000000000..ecc4523e0a34 --- /dev/null +++ b/emulators/py-nova/files/05-online-cpus.patch @@ -0,0 +1,63 @@ +From 8eb8fb92f21243ae0e41f2f626398d09582de29b Mon Sep 17 00:00:00 2001 +From: Alexander Nusov <alexander.nusov@nfvexpress.com> +Date: Fri, 25 Nov 2016 17:36:10 +0300 +Subject: [PATCH] add online cpu tracking option + +--- + nova/conf/libvirt.py | 3 +++ + nova/virt/libvirt/driver.py | 18 +++++++++++------- + 2 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py +index 2eba080..d133b03 100644 +--- a/nova/conf/libvirt.py ++++ b/nova/conf/libvirt.py +@@ -471,6 +471,9 @@ events`, refer https://libvirt.org/formatdomain.html#elementsPerf . + None + + """), ++ cfg.BoolOpt('online_cpu_tracking', ++ default=True, ++ help='Enable online cpu tracking'), + ] + + libvirt_imagebackend_opts = [ +diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py +index f9225de..f19ef70 100644 +--- a/nova/virt/libvirt/driver.py ++++ b/nova/virt/libvirt/driver.py +@@ -5188,11 +5188,12 @@ class LibvirtDriver(driver.ComputeDriver): + + cells = [] + allowed_cpus = hardware.get_vcpu_pin_set() +- online_cpus = self._host.get_online_cpus() +- if allowed_cpus: +- allowed_cpus &= online_cpus +- else: +- allowed_cpus = online_cpus ++ if CONF.libvirt.online_cpu_tracking: ++ online_cpus = self._host.get_online_cpus() ++ if allowed_cpus: ++ allowed_cpus &= online_cpus ++ else: ++ allowed_cpus = online_cpus + + def _get_reserved_memory_for_cell(self, cell_id, page_size): + cell = self._reserved_hugepages.get(cell_id, {}) +@@ -5205,8 +5206,11 @@ class LibvirtDriver(driver.ComputeDriver): + if cpu.siblings else () + for cpu in cell.cpus) + )) +- cpuset &= allowed_cpus +- siblings = [sib & allowed_cpus for sib in siblings] ++ if CONF.libvirt.online_cpu_tracking or allowed_cpus: ++ cpuset &= allowed_cpus ++ siblings = [sib & allowed_cpus for sib in siblings] ++ ++ + # Filter out singles and empty sibling sets that may be left + siblings = [sib for sib in siblings if len(sib) > 1] + +-- +2.8.1 + diff --git a/emulators/py-nova/files/06-freebsd-net.patch b/emulators/py-nova/files/06-freebsd-net.patch new file mode 100644 index 000000000000..365347e7e25c --- /dev/null +++ b/emulators/py-nova/files/06-freebsd-net.patch @@ -0,0 +1,1245 @@ +From 2dd71331d4d204466e7b066f62952990e55c2e24 Mon Sep 17 00:00:00 2001 +From: Alexander Nusov <alexander.nusov@nfvexpress.com> +Date: Tue, 29 Nov 2016 14:21:41 +0300 +Subject: [PATCH] add freebsd_net driver + +--- + nova/network/freebsd_net.py | 1226 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 1226 insertions(+) + create mode 100644 nova/network/freebsd_net.py + +diff --git a/nova/network/freebsd_net.py b/nova/network/freebsd_net.py +new file mode 100644 +index 0000000..b71fcf6 +--- /dev/null ++++ b/nova/network/freebsd_net.py +@@ -0,0 +1,1226 @@ ++# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. ++# Copyright 2010 United States Government as represented by the ++# Administrator of the National Aeronautics and Space Administration. ++# 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. ++ ++"""Implements vlans, bridges, and iptables rules using linux utilities.""" ++ ++import calendar ++import inspect ++import os ++import re ++import time ++import json ++ ++import netaddr ++import netifaces ++import socket ++import struct ++ ++from oslo_concurrency import processutils ++from oslo_log import log as logging ++from oslo_serialization import jsonutils ++from oslo_utils import excutils ++from oslo_utils import fileutils ++from oslo_utils import importutils ++from oslo_utils import timeutils ++import six ++ ++import nova.conf ++from nova import exception ++from nova.i18n import _, _LE, _LW ++from nova.network import model as network_model ++from nova import objects ++from nova.pci import utils as pci_utils ++from nova import utils ++ ++LOG = logging.getLogger(__name__) ++ ++ ++CONF = nova.conf.CONF ++ ++ ++# NOTE(vish): Iptables supports chain names of up to 28 characters, and we ++# add up to 12 characters to binary_name which is used as a prefix, ++# so we limit it to 16 characters. ++# (max_chain_name_length - len('-POSTROUTING') == 16) ++def get_binary_name(): ++ """Grab the name of the binary we're running in.""" ++ return os.path.basename(inspect.stack()[-1][1])[:16] ++ ++binary_name = get_binary_name() ++ ++ ++# NOTE(jkoelker) This is just a nice little stub point since mocking ++# builtins with mox is a nightmare ++def write_to_file(file, data, mode='w'): ++ with open(file, mode) as f: ++ f.write(data) ++ ++ ++def is_pid_cmdline_correct(pid, match): ++ """Ensure that the cmdline for a pid seems sane ++ ++ Because pids are recycled, blindly killing by pid is something to ++ avoid. This provides the ability to include a substring that is ++ expected in the cmdline as a safety check. ++ """ ++ try: ++ with open('/proc/%d/cmdline' % pid) as f: ++ cmdline = f.read() ++ return match in cmdline ++ except EnvironmentError: ++ return False ++ ++ ++def metadata_forward(): ++ """Create forwarding rule for metadata.""" ++ firewall_manager.add_rule("rdr proto tcp from any to 169.254.169.254 " ++ "port 80 -> %s port %s" % ++ (CONF.metadata_host, CONF.metadata_port)) ++ firewall_manager.add_rule("pass out route-to (lo0 127.0.0.1) proto tcp " ++ "from any to 169.254.169.254 port 80") ++ firewall_manager.apply() ++ ++ ++def metadata_accept(): ++ """Create the filter accept rule for metadata.""" ++ firewall_manager.add_rule("pass in inet proto tcp from any to " ++ "169.254.169.254 port = http " ++ "flags S/SA keep state") ++ firewall_manager.apply() ++ ++ ++def init_host(ip_range, is_external=False): ++ """Basic networking setup goes here.""" ++ # NOTE(devcamcar): Cloud public SNAT entries and the default ++ # SNAT rule for outbound traffic. ++ ++ firewall_manager.add_snat_rule(ip_range, is_external) ++ if is_external: ++ for snat_range in CONF.force_snat_range: ++ firewall_manager.add_rule("pass quick inet from %s to %s" % ++ (ip_range, snat_range)) ++ firewall_manager.add_rule("pass quick inet from %s to %s/32" % ++ (ip_range, CONF.metadata_host)) ++ for dmz in CONF.dmz_cidr: ++ firewall_manager.add_rule("pass quick inet from %s to %s" % ++ (ip_range, dmz)) ++ ++ """ ++ iptables_manager.ipv4['nat'].add_rule('POSTROUTING', ++ '-s %(range)s -d %(range)s ' ++ '-m conntrack ! --ctstate DNAT ' ++ '-j ACCEPT' % ++ {'range': ip_range}) ++ """ ++ firewall_manager.apply() ++ ++ ++def send_arp_for_ip(ip, device, count): ++ out, err = _execute('arping', '-U', '-i', device, '-c', str(count), ip, ++ run_as_root=True, check_exit_code=False) ++ ++ if err: ++ LOG.debug('arping error for IP %s', ip) ++ ++ ++def bind_floating_ip(floating_ip, device): ++ """Bind IP to public interface.""" ++ _execute('ifconfig', device, str(floating_ip) + '/32', 'add', ++ run_as_root=True, check_exit_code=0) ++ ++ if CONF.send_arp_for_ha and CONF.send_arp_for_ha_count > 0: ++ send_arp_for_ip(floating_ip, device, CONF.send_arp_for_ha_count) ++ ++ ++def unbind_floating_ip(floating_ip, device): ++ """Unbind a public IP from public interface.""" ++ _execute('ifconfig', device, str(floating_ip) + '/32', 'delete', ++ run_as_root=True, check_exit_code=0) ++ ++ ++def ensure_metadata_ip(): ++ """Sets up local metadata IP.""" ++ _execute('ifconfig', 'lo0', 'alias', '169.254.169.254/32', ++ run_as_root=True, check_exit_code=0) ++ ++ ++def ensure_vpn_forward(public_ip, port, private_ip): ++ """Sets up forwarding rules for vlan.""" ++ firewall_manager.add_rule("pass in proto udp " ++ "from any to %s port 1194 " % ++ (private_ip)) ++ firewall_manager.add_rule("rdr proto udp from any to %s port %s -> " ++ "%s port 1194" % ++ (public_ip, port, private_ip)) ++ firewall_manager.apply() ++ ++ ++def ensure_floating_forward(floating_ip, fixed_ip, device, network): ++ """Ensure floating IP forwarding rule.""" ++ firewall_manager.ensure_floating_rules(floating_ip, fixed_ip, device) ++ if device != network['bridge']: ++ firewall_manager.ensure_in_network_traffic_rules(fixed_ip, network) ++ firewall_manager.apply() ++ ++ ++def remove_floating_forward(floating_ip, fixed_ip, device, network): ++ """Remove forwarding for floating IP.""" ++ firewall_manager.remove_floating_rules(floating_ip, fixed_ip, device) ++ if device != network['bridge']: ++ firewall_manager.remove_in_network_traffic_rules(fixed_ip, network) ++ firewall_manager.apply() ++ ++ ++def clean_conntrack(fixed_ip): ++ pass ++ ++ ++def _enable_ipv4_forwarding(): ++ sysctl_key = 'net.inet.ip.forwarding' ++ stdout, stderr = _execute('sysctl', '-n', sysctl_key) ++ if stdout.strip() is not '1': ++ _execute('sysctl', '%s=1' % sysctl_key, run_as_root=True) ++ ++ ++@utils.synchronized('lock_gateway', external=True) ++def initialize_gateway_device(dev, network_ref): ++ if not network_ref: ++ return ++ ++ _enable_ipv4_forwarding() ++ ++ # NOTE(vish): The ip for dnsmasq has to be the first address on the ++ # bridge for it to respond to requests properly ++ try: ++ prefix = network_ref.cidr.prefixlen ++ except AttributeError: ++ prefix = network_ref['cidr'].rpartition('/')[2] ++ ++ full_ip = '%s/%s' % (network_ref['dhcp_server'], prefix) ++ new_ip_params = [['inet', full_ip, 'broadcast', network_ref['broadcast']]] ++ old_ip_params = [] ++ out, err = _execute('ifconfig', dev) ++ for line in out.split('\n'): ++ fields = line.split() ++ if fields and fields[0] == 'inet': ++ old_ip_params.append(fields) ++ if _address_to_cidr(fields[1], fields[3]) != full_ip: ++ new_ip_params.append(fields) ++ if not old_ip_params or _address_to_cidr(old_ip_params[0][1], old_ip_params[0][3]) != full_ip: ++ old_routes = [] ++ result = _execute('netstat', '-nrW', '-f', 'inet') ++ if result: ++ out, err = result ++ for line in out.split('\n'): ++ fields = line.split() ++ if len(fields) > 6 and (fields[6] == dev) and ('G' in fields[2]): ++ old_routes.append(fields) ++ _execute('route', '-q', 'delete', fields[0], fields[1], ++ run_as_root=True) ++ for ip_params in old_ip_params: ++ _execute(*_ifconfig_tail_cmd(dev, ip_params, 'delete'), ++ run_as_root=True) ++ for ip_params in new_ip_params: ++ _execute(*_ifconfig_tail_cmd(dev, ip_params, 'add'), ++ run_as_root=True) ++ ++ for fields in old_routes: ++ _execute('route', '-q', 'add', fields[0], fields[1], ++ run_as_root=True) ++ if CONF.send_arp_for_ha and CONF.send_arp_for_ha_count > 0: ++ send_arp_for_ip(network_ref['dhcp_server'], dev, ++ CONF.send_arp_for_ha_count) ++ if CONF.use_ipv6: ++ _execute('ifconfig', dev, 'inet6', network_ref['cidr_v6'], ++ run_as_root=True) ++ ++ ++def get_dhcp_leases(context, network_ref): ++ """Return a network's hosts config in dnsmasq leasefile format.""" ++ hosts = [] ++ host = None ++ if network_ref['multi_host']: ++ host = CONF.host ++ for fixedip in objects.FixedIPList.get_by_network(context, ++ network_ref, ++ host=host): ++ # NOTE(cfb): Don't return a lease entry if the IP isn't ++ # already leased ++ if fixedip.leased: ++ hosts.append(_host_lease(fixedip)) ++ ++ return '\n'.join(hosts) ++ ++ ++def get_dhcp_hosts(context, network_ref, fixedips): ++ """Get network's hosts config in dhcp-host format.""" ++ hosts = [] ++ macs = set() ++ for fixedip in fixedips: ++ if fixedip.allocated: ++ if fixedip.virtual_interface.address not in macs: ++ hosts.append(_host_dhcp(fixedip)) ++ macs.add(fixedip.virtual_interface.address) ++ return '\n'.join(hosts) ++ ++ ++def get_dns_hosts(context, network_ref): ++ """Get network's DNS hosts in hosts format.""" ++ hosts = [] ++ for fixedip in objects.FixedIPList.get_by_network(context, network_ref): ++ if fixedip.allocated: ++ hosts.append(_host_dns(fixedip)) ++ return '\n'.join(hosts) ++ ++ ++def _add_dnsmasq_accept_rules(dev): ++ """Allow DHCP and DNS traffic through to dnsmasq.""" ++ for port in [67, 53]: ++ for proto in ['udp', 'tcp']: ++ firewall_manager.add_rule("pass in on %s inet proto %s " ++ "from any to any port %s" % ++ (dev, proto, port)) ++ firewall_manager.apply() ++ ++ ++def _remove_dnsmasq_accept_rules(dev): ++ """Remove DHCP and DNS traffic allowed through to dnsmasq.""" ++ for port in [67, 53]: ++ for proto in ['udp', 'tcp']: ++ firewall_manager.remove_rule("pass in on %s inet proto %s " ++ "from any to any port %s" % ++ (dev, proto, port)) ++ firewall_manager.apply() ++ ++ ++def get_dhcp_opts(context, network_ref, fixedips): ++ """Get network's hosts config in dhcp-opts format.""" ++ gateway = network_ref['gateway'] ++ # NOTE(vish): if we are in multi-host mode and we are not sharing ++ # addresses, then we actually need to hand out the ++ # dhcp server address as the gateway. ++ if network_ref['multi_host'] and not (network_ref['share_address'] or ++ CONF.share_dhcp_address): ++ gateway = network_ref['dhcp_server'] ++ hosts = [] ++ if CONF.use_single_default_gateway: ++ for fixedip in fixedips: ++ if fixedip.allocated: ++ vif_id = fixedip.virtual_interface_id ++ if fixedip.default_route: ++ hosts.append(_host_dhcp_opts(vif_id, gateway)) ++ else: ++ hosts.append(_host_dhcp_opts(vif_id)) ++ else: ++ hosts.append(_host_dhcp_opts(None, gateway)) ++ return '\n'.join(hosts) ++ ++ ++def release_dhcp(dev, address, mac_address): ++ if device_exists(dev): ++ try: ++ utils.execute('dhcp_release', dev, address, mac_address, ++ run_as_root=True) ++ except processutils.ProcessExecutionError: ++ raise exception.NetworkDhcpReleaseFailed(address=address, ++ mac_address=mac_address) ++ ++ ++def update_dhcp(context, dev, network_ref): ++ conffile = _dhcp_file(dev, 'conf') ++ host = None ++ if network_ref['multi_host']: ++ host = CONF.host ++ fixedips = objects.FixedIPList.get_by_network(context, ++ network_ref, ++ host=host) ++ write_to_file(conffile, get_dhcp_hosts(context, network_ref, fixedips)) ++ restart_dhcp(context, dev, network_ref, fixedips) ++ ++ ++def update_dns(context, dev, network_ref): ++ hostsfile = _dhcp_file(dev, 'hosts') ++ host = None ++ if network_ref['multi_host']: ++ host = CONF.host ++ fixedips = objects.FixedIPList.get_by_network(context, ++ network_ref, ++ host=host) ++ write_to_file(hostsfile, get_dns_hosts(context, network_ref)) ++ restart_dhcp(context, dev, network_ref, fixedips) ++ ++ ++def kill_dhcp(dev): ++ pid = _dnsmasq_pid_for(dev) ++ if pid: ++ # Check that the process exists and looks like a dnsmasq process ++ conffile = _dhcp_file(dev, 'conf') ++ if is_pid_cmdline_correct(pid, conffile.split('/')[-1]): ++ _execute('kill', '-9', pid, run_as_root=True) ++ else: ++ LOG.debug('Pid %d is stale, skip killing dnsmasq', pid) ++ _remove_dnsmasq_accept_rules(dev) ++ ++ ++# NOTE(ja): Sending a HUP only reloads the hostfile, so any ++# configuration options (like dchp-range, vlan, ...) ++# aren't reloaded. ++@utils.synchronized('dnsmasq_start') ++def restart_dhcp(context, dev, network_ref, fixedips): ++ """(Re)starts a dnsmasq server for a given network. ++ ++ If a dnsmasq instance is already running then send a HUP ++ signal causing it to reload, otherwise spawn a new instance. ++ ++ """ ++ conffile = _dhcp_file(dev, 'conf') ++ ++ optsfile = _dhcp_file(dev, 'opts') ++ write_to_file(optsfile, get_dhcp_opts(context, network_ref, fixedips)) ++ os.chmod(optsfile, 0o644) ++ ++ # Make sure dnsmasq can actually read it (it setuid()s to "nobody") ++ os.chmod(conffile, 0o644) ++ ++ pid = _dnsmasq_pid_for(dev) ++ ++ # if dnsmasq is already running, then tell it to reload ++ if pid: ++ if is_pid_cmdline_correct(pid, conffile.split('/')[-1]): ++ try: ++ _execute('kill', '-HUP', pid, run_as_root=True) ++ _add_dnsmasq_accept_rules(dev) ++ return ++ except Exception as exc: ++ LOG.error(_LE('kill -HUP dnsmasq threw %s'), exc) ++ else: ++ LOG.debug('Pid %d is stale, relaunching dnsmasq', pid) ++ ++ cmd = ['env', ++ 'CONFIG_FILE=%s' % jsonutils.dumps(CONF.dhcpbridge_flagfile), ++ 'NETWORK_ID=%s' % str(network_ref['id']), ++ 'dnsmasq', ++ '--strict-order', ++ '--bind-interfaces', ++ '--conf-file=%s' % CONF.dnsmasq_config_file, ++ '--pid-file=%s' % _dhcp_file(dev, 'pid'), ++ '--dhcp-optsfile=%s' % _dhcp_file(dev, 'opts'), ++ '--listen-address=%s' % network_ref['dhcp_server'], ++ '--except-interface=lo', ++ '--dhcp-range=set:%s,%s,static,%s,%ss' % ++ (network_ref['label'], ++ network_ref['dhcp_start'], ++ network_ref['netmask'], ++ CONF.dhcp_lease_time), ++ '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(network_ref['cidr'])), ++ '--dhcp-hostsfile=%s' % _dhcp_file(dev, 'conf'), ++ '--dhcp-script=%s' % CONF.dhcpbridge, ++ '--no-hosts', ++ '--leasefile-ro'] ++ ++ # dnsmasq currently gives an error for an empty domain, ++ # rather than ignoring. So only specify it if defined. ++ if CONF.dhcp_domain: ++ cmd.append('--domain=%s' % CONF.dhcp_domain) ++ ++ dns_servers = CONF.dns_server ++ if CONF.use_network_dns_servers: ++ if network_ref.get('dns1'): ++ dns_servers.append(network_ref.get('dns1')) ++ if network_ref.get('dns2'): ++ dns_servers.append(network_ref.get('dns2')) ++ if network_ref['multi_host']: ++ cmd.append('--addn-hosts=%s' % _dhcp_file(dev, 'hosts')) ++ if dns_servers: ++ cmd.append('--no-resolv') ++ for dns_server in dns_servers: ++ cmd.append('--server=%s' % dns_server) ++ ++ _execute(*cmd, run_as_root=True) ++ ++ _add_dnsmasq_accept_rules(dev) ++ ++ ++@utils.synchronized('radvd_start') ++def update_ra(context, dev, network_ref): ++ conffile = _ra_file(dev, 'conf') ++ conf_str = """ ++interface %s ++{ ++ AdvSendAdvert on; ++ MinRtrAdvInterval 3; ++ MaxRtrAdvInterval 10; ++ prefix %s ++ { ++ AdvOnLink on; ++ AdvAutonomous on; ++ }; ++}; ++""" % (dev, network_ref['cidr_v6']) ++ write_to_file(conffile, conf_str) ++ ++ # Make sure radvd can actually read it (it setuid()s to "nobody") ++ os.chmod(conffile, 0o644) ++ ++ pid = _ra_pid_for(dev) ++ ++ # if radvd is already running, then tell it to reload ++ if pid: ++ if is_pid_cmdline_correct(pid, conffile): ++ try: ++ _execute('kill', pid, run_as_root=True) ++ except Exception as exc: ++ LOG.error(_LE('killing radvd threw %s'), exc) ++ else: ++ LOG.debug('Pid %d is stale, relaunching radvd', pid) ++ ++ cmd = ['radvd', ++ '-C', '%s' % _ra_file(dev, 'conf'), ++ '-p', '%s' % _ra_file(dev, 'pid')] ++ ++ _execute(*cmd, run_as_root=True) ++ ++ ++def _host_lease(fixedip): ++ """Return a host string for an address in leasefile format.""" ++ timestamp = timeutils.utcnow() ++ seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) ++ return '%d %s %s %s *' % (seconds_since_epoch + CONF.dhcp_lease_time, ++ fixedip.virtual_interface.address, ++ fixedip.address, ++ fixedip.instance.hostname or '*') ++ ++ ++def _host_dhcp_network(vif_id): ++ return 'NW-%s' % vif_id ++ ++ ++def _host_dhcp(fixedip): ++ """Return a host string for an address in dhcp-host format.""" ++ # NOTE(cfb): dnsmasq on linux only supports 64 characters in the hostname ++ # field (LP #1238910). Since the . counts as a character we need ++ # to truncate the hostname to only 63 characters. ++ hostname = fixedip.instance.hostname ++ if len(hostname) > 63: ++ LOG.warning(_LW('hostname %s too long, truncating.'), hostname) ++ hostname = fixedip.instance.hostname[:2] + '-' +\ ++ fixedip.instance.hostname[-60:] ++ if CONF.use_single_default_gateway: ++ net = _host_dhcp_network(fixedip.virtual_interface_id) ++ return '%s,%s.%s,%s,net:%s' % (fixedip.virtual_interface.address, ++ hostname, ++ CONF.dhcp_domain, ++ fixedip.address, ++ net) ++ else: ++ return '%s,%s.%s,%s' % (fixedip.virtual_interface.address, ++ hostname, ++ CONF.dhcp_domain, ++ fixedip.address) ++ ++ ++def _host_dns(fixedip): ++ return '%s\t%s.%s' % (fixedip.address, ++ fixedip.instance.hostname, ++ CONF.dhcp_domain) ++ ++ ++def _host_dhcp_opts(vif_id=None, gateway=None): ++ """Return an empty gateway option.""" ++ values = [] ++ if vif_id is not None: ++ values.append(_host_dhcp_network(vif_id)) ++ # NOTE(vish): 3 is the dhcp option for gateway. ++ values.append('3') ++ if gateway: ++ values.append('%s' % gateway) ++ return ','.join(values) ++ ++ ++def _execute(*cmd, **kwargs): ++ """Wrapper around utils._execute for fake_network.""" ++ if CONF.fake_network: ++ LOG.debug('FAKE NET: %s', ' '.join(map(str, cmd))) ++ return 'fake', 0 ++ else: ++ return utils.execute(*cmd, **kwargs) ++ ++ ++def device_exists(device): ++ """Check if ethernet device exists.""" ++ try: ++ _execute('ifconfig', device, run_as_root=True, check_exit_code=[0]) ++ except processutils.ProcessExecutionError: ++ return False ++ else: ++ return True ++ ++ ++def _dhcp_file(dev, kind): ++ """Return path to a pid, leases, hosts or conf file for a bridge/device.""" ++ fileutils.ensure_tree(CONF.networks_path) ++ return os.path.abspath('%s/nova-%s.%s' % (CONF.networks_path, ++ dev, ++ kind)) ++ ++ ++def _ra_file(dev, kind): ++ """Return path to a pid or conf file for a bridge/device.""" ++ fileutils.ensure_tree(CONF.networks_path) ++ return os.path.abspath('%s/nova-ra-%s.%s' % (CONF.networks_path, ++ dev, ++ kind)) ++ ++ ++def _dnsmasq_pid_for(dev): ++ """Returns the pid for prior dnsmasq instance for a bridge/device. ++ ++ Returns None if no pid file exists. ++ ++ If machine has rebooted pid might be incorrect (caller should check). ++ ++ """ ++ pid_file = _dhcp_file(dev, 'pid') ++ ++ if os.path.exists(pid_file): ++ try: ++ with open(pid_file, 'r') as f: ++ return int(f.read()) ++ except (ValueError, IOError): ++ return None ++ ++ ++def _ra_pid_for(dev): ++ """Returns the pid for prior radvd instance for a bridge/device. ++ ++ Returns None if no pid file exists. ++ ++ If machine has rebooted pid might be incorrect (caller should check). ++ ++ """ ++ pid_file = _ra_file(dev, 'pid') ++ ++ if os.path.exists(pid_file): ++ with open(pid_file, 'r') as f: ++ return int(f.read()) ++ ++ ++def _address_to_cidr(address, hexmask): ++ """Produce a CIDR format address/netmask.""" ++ netmask = socket.inet_ntoa(struct.pack(">I", int(hexmask, 16))) ++ ip_cidr = netaddr.IPNetwork("%s/%s" % (address, netmask)) ++ return str(ip_cidr) ++ ++ ++def _ifconfig_tail_cmd(netif, params, action): ++ """Construct ifconfig command""" ++ cmd = ['ifconfig', netif] ++ cmd.extend(params) ++ cmd.extend([action]) ++ return cmd ++ ++ ++def _set_device_mtu(dev, mtu=None): ++ """Set the device MTU.""" ++ if mtu: ++ utils.execute('ifconfig', dev, 'mtu', mtu, ++ run_as_root=True, check_exit_code=0) ++ ++ ++def _ovs_vsctl(args): ++ full_args = ['ovs-vsctl', '--timeout=%s' % CONF.ovs_vsctl_timeout] + args ++ try: ++ return utils.execute(*full_args, run_as_root=True) ++ except Exception as e: ++ LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"), ++ {'cmd': full_args, 'exception': e}) ++ raise exception.OvsConfigurationFailure(inner_exception=e) ++ ++ ++def _create_ovs_vif_cmd(bridge, dev, iface_id, mac, ++ instance_id, interface_type=None): ++ cmd = ['--', '--if-exists', 'del-port', dev, '--', ++ 'add-port', bridge, dev, ++ '--', 'set', 'Interface', dev, ++ 'external-ids:iface-id=%s' % iface_id, ++ 'external-ids:iface-status=active', ++ 'external-ids:attached-mac=%s' % mac, ++ 'external-ids:vm-uuid=%s' % instance_id] ++ if interface_type: ++ cmd += ['type=%s' % interface_type] ++ return cmd ++ ++ ++def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, ++ mtu=None, interface_type=None): ++ _ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id, ++ mac, instance_id, ++ interface_type)) ++ # Note at present there is no support for setting the ++ # mtu for vhost-user type ports. ++ if interface_type != network_model.OVS_VHOSTUSER_INTERFACE_TYPE: ++ _set_device_mtu(dev, mtu) ++ else: ++ LOG.debug("MTU not set on %(interface_name)s interface " ++ "of type %(interface_type)s.", ++ {'interface_name': dev, ++ 'interface_type': interface_type}) ++ ++ ++def delete_ovs_vif_port(bridge, dev, delete_dev=True): ++ _ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev]) ++ if delete_dev: ++ delete_net_dev(dev) ++ ++ ++def create_tap_dev(dev, mac_address=None): ++ if not device_exists(dev): ++ utils.execute('ifconfig', 'tap', 'create', 'name', dev, ++ run_as_root=True, check_exit_code=[0]) ++ if mac_address: ++ utils.execute('ifconfig', dev, 'ether', mac_address, ++ run_as_root=True, check_exit_code=[0]) ++ utils.execute('ifconfig', dev, 'up', ++ run_as_root=True, check_exit_code=[0]) ++ ++ ++def delete_net_dev(dev): ++ """Delete a network device only if it exists.""" ++ if device_exists(dev): ++ try: ++ utils.execute('ifconfig', dev, 'destroy', ++ run_as_root=True, check_exit_code=0) ++ LOG.debug("Net device removed: '%s'", dev) ++ except processutils.ProcessExecutionError: ++ with excutils.save_and_reraise_exception(): ++ LOG.error(_LE("Failed removing net device: '%s'"), dev) ++ ++ ++def delete_bridge_dev(dev): ++ """Delete a network bridge.""" ++ if device_exists(dev): ++ try: ++ utils.execute('ifconfig', dev, 'down', run_as_root=True) ++ utils.execute('ifconfig', dev, 'destroy', run_as_root=True) ++ except processutils.ProcessExecutionError: ++ with excutils.save_and_reraise_exception(): ++ LOG.error(_LE("Failed removing bridge device: '%s'"), dev) ++ ++ ++# Similar to compute virt layers, the FreeBSD network node ++# code uses a flexible driver model to support different ways ++# of creating ethernet interfaces and attaching them to the network. ++# In the case of a network host, these interfaces ++# act as gateway/dhcp/vpn/etc. endpoints not VM interfaces. ++interface_driver = None ++ ++ ++def _get_interface_driver(): ++ global interface_driver ++ if not interface_driver: ++ interface_driver = importutils.import_object( ++ CONF.freebsdnet_interface_driver) ++ return interface_driver ++ ++ ++def plug(network, mac_address, gateway=True): ++ return _get_interface_driver().plug(network, mac_address, gateway) ++ ++ ++def unplug(network): ++ return _get_interface_driver().unplug(network) ++ ++ ++def get_dev(network): ++ return _get_interface_driver().get_dev(network) ++ ++ ++class FreeBSDNetInterfaceDriver(object): ++ """Abstract class that defines generic network host API ++ for all FreeBSD interface drivers. ++ """ ++ ++ def plug(self, network, mac_address): ++ """Create FreeBSD device, return device name.""" ++ raise NotImplementedError() ++ ++ def unplug(self, network): ++ """Destroy FreeBSD device, return device name.""" ++ raise NotImplementedError() ++ ++ def get_dev(self, network): ++ """Get device name.""" ++ raise NotImplementedError() ++ ++ ++# plugs interfaces using FreeBSD Bridge ++class FreeBSDBridgeInterfaceDriver(FreeBSDNetInterfaceDriver): ++ ++ def plug(self, network, mac_address, gateway=True): ++ vlan = network.get('vlan') ++ if vlan is not None: ++ iface = CONF.vlan_interface or network['bridge_interface'] ++ FreeBSDBridgeInterfaceDriver.ensure_vlan_bridge( ++ vlan, ++ network['bridge'], ++ iface, ++ network, ++ mac_address, ++ network.get('mtu')) ++ iface = 'vlan%s' % vlan ++ else: ++ iface = CONF.flat_interface or network['bridge_interface'] ++ FreeBSDBridgeInterfaceDriver.ensure_bridge( ++ network['bridge'], ++ iface, ++ network, gateway) ++ ++ if network['share_address'] or CONF.share_dhcp_address: ++ isolate_dhcp_address(iface, network['dhcp_server']) ++ # NOTE(vish): applying here so we don't get a lock conflict ++ firewall_manager.apply() ++ return network['bridge'] ++ ++ def unplug(self, network, gateway=True): ++ vlan = network.get('vlan') ++ if vlan is not None: ++ iface = 'vlan%s' % vlan ++ FreeBSDBridgeInterfaceDriver.remove_vlan_bridge(vlan, ++ network['bridge']) ++ else: ++ iface = CONF.flat_interface or network['bridge_interface'] ++ FreeBSDBridgeInterfaceDriver.remove_bridge(network['bridge'], ++ gateway) ++ ++ if network['share_address'] or CONF.share_dhcp_address: ++ remove_isolate_dhcp_address(iface, network['dhcp_server']) ++ ++ firewall_manager.apply() ++ return self.get_dev(network) ++ ++ def get_dev(self, network): ++ return network['bridge'] ++ ++ @staticmethod ++ def ensure_vlan_bridge(vlan_num, bridge, bridge_interface, ++ net_attrs=None, mac_address=None, ++ mtu=None): ++ """Create a vlan and bridge unless they already exist.""" ++ interface = FreeBSDBridgeInterfaceDriver.ensure_vlan(vlan_num, ++ bridge_interface, mac_address, ++ mtu) ++ FreeBSDBridgeInterfaceDriver.ensure_bridge(bridge, interface, net_attrs) ++ return interface ++ ++ @staticmethod ++ def remove_vlan_bridge(vlan_num, bridge): ++ """Delete a bridge and vlan.""" ++ FreeBSDBridgeInterfaceDriver.remove_bridge(bridge) ++ FreeBSDBridgeInterfaceDriver.remove_vlan(vlan_num) ++ ++ @staticmethod ++ @utils.synchronized('lock_vlan', external=True) ++ def ensure_vlan(vlan_num, bridge_interface, mac_address=None, mtu=None, ++ interface=None): ++ """Create a vlan unless it already exists.""" ++ if interface is None: ++ interface = 'vlan%s' % vlan_num ++ if not device_exists(interface): ++ LOG.debug('Starting VLAN interface %s', interface) ++ out, err = _execute('ifconfig', 'vlan', 'create', ++ 'vlan', vlan_num, ++ 'vlandev', bridge_interface, ++ 'name', interface, ++ run_as_root=True) ++ if err and 'File exists' not in err: ++ msg = _('Failed to add vlan: %s') % err ++ raise exception.NovaException(msg) ++ # (danwent) the bridge will inherit this address, so we want to ++ # make sure it is the value set from the NetworkManager ++ if mac_address: ++ _execute('ifconfig', interface, 'ether', mac_address, ++ run_as_root=True) ++ _execute('ifconfig',interface, 'up', ++ run_as_root=True) ++ # NOTE(vish): set mtu every time to ensure that changes to mtu get ++ # propagated ++ _set_device_mtu(interface, mtu) ++ return interface ++ ++ @staticmethod ++ @utils.synchronized('lock_vlan', external=True) ++ def remove_vlan(vlan_num): ++ """Delete a vlan.""" ++ vlan_interface = 'vlan%s' % vlan_num ++ delete_net_dev(vlan_interface) ++ ++ @staticmethod ++ @utils.synchronized('lock_bridge', external=True) ++ def ensure_bridge(bridge, interface, net_attrs=None, gateway=True, ++ filtering=True): ++ """Create a bridge unless it already exists. ++ ++ :param interface: the interface to create the bridge on. ++ :param net_attrs: dictionary with attributes used to create bridge. ++ :param gateway: whether or not the bridge is a gateway. ++ :param filtering: whether or not to create filters on the bridge. ++ ++ If net_attrs is set, it will add the net_attrs['gateway'] to the bridge ++ using net_attrs['broadcast'] and net_attrs['cidr']. It will also add ++ the ip_v6 address specified in net_attrs['cidr_v6'] if use_ipv6 is set. ++ ++ The code will attempt to move any IPs that already exist on the ++ interface onto the bridge and reset the default gateway if necessary. ++ ++ """ ++ if not device_exists(bridge): ++ LOG.debug('Starting Bridge %s', bridge) ++ out, err = _execute('ifconfig', 'bridge', 'create', 'name', bridge, ++ check_exit_code=False, run_as_root=True) ++ if err and 'File exists' not in err: ++ msg = _('Failed to add bridge: %s') % err ++ raise exception.NovaException(msg) ++ ++ _execute('ifconfig', bridge, 'up', run_as_root=True) ++ ++ if interface: ++ LOG.debug('Adding interface %(interface)s to bridge %(bridge)s', ++ {'interface': interface, 'bridge': bridge}) ++ out, err = _execute('ifconfig', bridge, 'addm', interface, ++ check_exit_code=False, run_as_root=True) ++ if err and 'File exists' not in err: ++ msg = _('Failed to add interface: %s') % err ++ raise exception.NovaException(msg) ++ ++ # NOTE(apmelton): Linux bridge's default behavior is to use the ++ # lowest mac of all plugged interfaces. This isn't a problem when ++ # it is first created and the only interface is the bridged ++ # interface. But, as instance interfaces are plugged, there is a ++ # chance for the mac to change. So, set it here so that it won't ++ # change in the future. ++ if not CONF.fake_network: ++ interface_addrs = netifaces.ifaddresses(interface) ++ interface_mac = interface_addrs[netifaces.AF_LINK][0]['addr'] ++ _execute('ifconfig', bridge, 'ether', interface_mac, ++ run_as_root=True) ++ ++ out, err = _execute('ifconfig', interface, 'up', ++ check_exit_code=False, run_as_root=True) ++ ++ # NOTE(vish): This will break if there is already an ip on the ++ # interface, so we move any ips to the bridge ++ # NOTE(danms): We also need to copy routes to the bridge so as ++ # not to break existing connectivity on the interface ++ old_routes = [] ++ out, err = _execute('netstat', '-nrW', '-f', 'inet') ++ for line in out.split('\n'): ++ fields = line.split() ++ if len(fields) > 6 and (fields[6] == interface) and ('G' in fields[2]): ++ old_routes.append(fields) ++ _execute('route', '-q', 'delete', fields[0], fields[1], ++ run_as_root=True) ++ out, err = _execute('ifconfig', interface) ++ for line in out.split('\n'): ++ fields = line.split() ++ if fields and fields[0] == 'inet': ++ _execute(*_ifconfig_tail_cmd(interface, fields, 'delete'), ++ run_as_root=True) ++ _execute(*_ifconfig_tail_cmd(bridge, fields, 'add'), ++ run_as_root=True) ++ for fields in old_routes: ++ _execute('route', '-q', 'add', fields[0], fields[1], ++ run_as_root=True) ++ ++ if filtering: ++ # Don't forward traffic unless we were told to be a gateway ++ if gateway: ++ firewall_manager.ensure_gateway_rules(bridge) ++ else: ++ firewall_manager.ensure_bridge_rules(bridge) ++ ++ @staticmethod ++ @utils.synchronized('lock_bridge', external=True) ++ def remove_bridge(bridge, gateway=True, filtering=True): ++ """Delete a bridge.""" ++ if not device_exists(bridge): ++ return ++ else: ++ if filtering: ++ if gateway: ++ firewall_manager.remove_gateway_rules(bridge) ++ else: ++ firewall_manager.remove_bridge_rules(bridge) ++ delete_bridge_dev(bridge) ++ ++ ++def isolate_dhcp_address(interface, address): ++ # block arp traffic to address across the interface ++ firewall_manager.ensure_dhcp_isolation(interface, address) ++ ++ ++def remove_isolate_dhcp_address(interface, address): ++ # block arp traffic to address across the interface ++ firewall_manager.remove_dhcp_isolation(interface, address) ++ ++ ++# plugs interfaces using Open vSwitch ++class FreeBSDOVSInterfaceDriver(FreeBSDNetInterfaceDriver): ++ ++ def plug(self, network, mac_address, gateway=True): ++ dev = self.get_dev(network) ++ if not device_exists(dev): ++ bridge = CONF.freebsdnet_ovs_integration_bridge ++ _ovs_vsctl(['--', '--may-exist', 'add-port', bridge, dev, ++ '--', 'set', 'Interface', dev, 'type=internal', ++ '--', 'set', 'Interface', dev, ++ 'external-ids:iface-id=%s' % dev, ++ '--', 'set', 'Interface', dev, ++ 'external-ids:iface-status=active', ++ '--', 'set', 'Interface', dev, ++ 'external-ids:attached-mac=%s' % mac_address]) ++ _execute('ifconfig', dev, 'ether', mac_address, run_as_root=True) ++ _set_device_mtu(dev, network.get('mtu')) ++ _execute('ifconfig', dev, 'up', run_as_root=True) ++ if not gateway: ++ # If we weren't instructed to act as a gateway then add the ++ # appropriate flows to block all non-dhcp traffic. ++ _execute('ovs-ofctl', ++ 'add-flow', bridge, 'priority=1,actions=drop', ++ run_as_root=True) ++ _execute('ovs-ofctl', 'add-flow', bridge, ++ 'udp,tp_dst=67,dl_dst=%s,priority=2,actions=normal' % ++ mac_address, run_as_root=True) ++ # .. and make sure iptbles won't forward it as well. ++ firewall_manager.ensure_bridge_rules(bridge) ++ else: ++ firewall_manager.ensure_gateway_rules(bridge) ++ ++ return dev ++ ++ def unplug(self, network): ++ dev = self.get_dev(network) ++ bridge = CONF.freebsdnet_ovs_integration_bridge ++ _ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev]) ++ return dev ++ ++ def get_dev(self, network): ++ dev = 'gw-' + str(network['uuid'][0:11]) ++ return dev ++ ++ ++# plugs interfaces using FreeBSD Bridge when using NeutronManager ++class NeutronFreeBSDBridgeInterfaceDriver(FreeBSDNetInterfaceDriver): ++ ++ BRIDGE_NAME_PREFIX = 'brq' ++ GATEWAY_INTERFACE_PREFIX = 'gw-' ++ ++ def plug(self, network, mac_address, gateway=True): ++ dev = self.get_dev(network) ++ bridge = self.get_bridge(network) ++ if not gateway: ++ # If we weren't instructed to act as a gateway then add the ++ # appropriate flows to block all non-dhcp traffic. ++ # .. and make sure iptbles won't forward it as well. ++ firewall_manager.ensure_bridge_rules(bridge) ++ return bridge ++ else: ++ firewall_manager.ensure_gateway_rules(bridge) ++ ++ create_tap_dev(dev, mac_address) ++ ++ if not device_exists(bridge): ++ LOG.debug("Starting bridge %s ", bridge) ++ utils.execute('ifconfig', 'bridge', 'create', 'name', bridge, run_as_root=True) ++ utils.execute('ifconfig', bridge, 'ether', mac_address, run_as_root=True) ++ utils.execute('ifconfig', bridge, 'up', run_as_root=True) ++ LOG.debug("Done starting bridge %s", bridge) ++ ++ full_ip = '%s/%s' % (network['dhcp_server'], ++ network['cidr'].rpartition('/')[2]) ++ utils.execute('ifconfig', bridge, full_ip, 'add', run_as_root=True) ++ ++ return dev ++ ++ def unplug(self, network): ++ dev = self.get_dev(network) ++ if not device_exists(dev): ++ return None ++ else: ++ delete_net_dev(dev) ++ return dev ++ ++ def get_dev(self, network): ++ dev = self.GATEWAY_INTERFACE_PREFIX + str(network['uuid'][0:11]) ++ return dev ++ ++ def get_bridge(self, network): ++ bridge = self.BRIDGE_NAME_PREFIX + str(network['uuid'][0:11]) ++ return bridge ++ ++ ++class FirewallManager(object): ++ def __init__(self, execute=_execute): ++ self.execute = execute ++ self.apply_deferred = False ++ self.anchor = 'org.openstack/%s' % get_binary_name() ++ self.rules = { ++ "translation": [], ++ "filtering": [] ++ } ++ self.is_dirty = False ++ ++ def _get_rule_section(self, rule): ++ LOG.warning("processing rule: %s" % rule) ++ head, tail = rule.split(' ', 1) ++ if head in ('nat', 'rdr'): ++ return 'translation' ++ elif head in ('pass', 'block'): ++ return 'filtering' ++ else: ++ return None ++ ++ def add_rule(self, rule): ++ cleaned_rule = rule.strip() ++ section = self._get_rule_section(cleaned_rule) ++ if section: ++ if cleaned_rule not in self.rules[section]: ++ self.rules[section].append(cleaned_rule) ++ self.is_dirty = True ++ LOG.warning("Added rule to %s: %s", section, cleaned_rule) ++ ++ def remove_rule(self, rule): ++ cleaned_rule = rule.strip() ++ section = self._get_rule_section(cleaned_rule) ++ LOG.warning("Removing rule from %s: %s", section, cleaned_rule) ++ if section: ++ try: ++ self.rules[section].remove(cleaned_rule) ++ self.is_dirty = True ++ except: ++ pass ++ ++ def defer_apply_on(self): ++ self.apply_deferred = True ++ ++ def defer_apply_off(self): ++ self.apply_deferred = False ++ self.apply() ++ ++ def dirty(self): ++ return self.is_dirty ++ ++ def apply(self): ++ if self.apply_deferred: ++ return ++ if self.dirty(): ++ self._apply() ++ else: ++ LOG.debug("Skipping apply due to lack of new rules") ++ ++ @utils.synchronized('pfctl', external=True) ++ def _apply(self): ++ all_lines = [] ++ all_lines.extend(self.rules['translation']) ++ all_lines.extend(self.rules['filtering']) ++ all_lines.extend(["\n"]) ++ ++ self.is_dirty = False ++ self.execute("pfctl", "-a", self.anchor, "-f", "-", ++ process_input="\n".join(all_lines), ++ run_as_root=True) ++ LOG.warning("FirewallManager.apply completed with success") ++ ++ def get_gateway_rules(self, bridge): ++ LOG.warning("FirewallManager.get_gateway_rules: " ++ "Please configure rules in pf.conf") ++ return [] ++ ++ def ensure_gateway_rules(self, bridge): ++ for rule in self.get_gateway_rules(bridge): ++ self.add_rule(rule) ++ ++ def remove_gateway_rules(self, bridge): ++ for rule in self.get_gateway_rules(bridge): ++ self.remove_rule(rule) ++ ++ def ensure_bridge_rules(self, bridge): ++ LOG.warning("FirewallManager.ensure_bridge_rules: " ++ "Please configure rules in pf.conf") ++ ++ def remove_bridge_rules(self, bridge): ++ LOG.warning("FirewallManager.remove_bridge_rules: " ++ "Please configure rules in pf.conf") ++ ++ def ensure_dhcp_isolation(self, interface, address): ++ LOG.warning("FirewallManager.ensure_dhcp_isolation: " ++ "DHCP isolation is not yet implemented") ++ ++ def remove_dhcp_isolation(self, interface, address): ++ LOG.warning("FirewallManager.remove_dhcp_isolation: " ++ "DHCP isolation is not yet implemented") ++ ++ def ensure_in_network_traffic_rules(self, fixed_ip, network): ++ LOG.warning("FirewallManager.ensure_in_network_traffic_rules: " ++ "Please configure rules in pf.conf") ++ ++ def remove_in_network_traffic_rules(self, fixed_ip, network): ++ LOG.warning("FirewallManager.remove_in_network_traffic_rules: " ++ "Please configure rules in pf.conf") ++ ++ def floating_forward_rules(self, floating_ip, fixed_ip, device): ++ rules = [] ++ rules.append("rdr inet from any to %s -> %s" % (floating_ip, fixed_ip)) ++ ++ return rules ++ ++ def ensure_floating_rules(self, floating_ip, fixed_ip, device): ++ for rule in self.floating_forward_rules(floating_ip, fixed_ip, device): ++ self.add_rule(rule) ++ ++ def remove_floating_rules(self, floating_ip, fixed_ip, device): ++ for rule in self.floating_forward_rules(floating_ip, fixed_ip, device): ++ self.remove_rule(rule) ++ ++ def add_snat_rule(self, ip_range, is_external=False): ++ if CONF.routing_source_ip: ++ if is_external: ++ if CONF.force_snat_range: ++ snat_range = CONF.force_snat_range ++ else: ++ snat_range = [] ++ else: ++ snat_range = ['0.0.0.0/0'] ++ for dest_range in snat_range: ++ if not is_external and CONF.public_interface: ++ firewall_manager.add_rule("nat on %s inet from %s to %s -> %s" % ++ (CONF.public_interface, ++ ip_range, ++ dest_range, ++ CONF.routing_source_ip)) ++ else: ++ firewall_manager.add_rule("nat inet from %s to %s -> %s" % ++ (ip_range, ++ dest_range, ++ CONF.routing_source_ip)) ++ firewall_manager.apply() ++ ++ ++firewall_manager = FirewallManager() ++ ++ ++def get_firewall_manager(): ++ return firewall_manager +-- +2.8.1 + diff --git a/emulators/py-nova/files/nova-api.in b/emulators/py-nova/files/nova-api.in new file mode 100644 index 000000000000..163125139d74 --- /dev/null +++ b/emulators/py-nova/files/nova-api.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_api +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_api: +# +# nova_api_enable="YES" +# +# nova_api_enable (bool): +# Set it to "YES" to enable nova_api. +# Default is "NO". +# +# nova_api_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_api_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_api_logdir}/nova-api.log" +# + +. /etc/rc.subr + +name=nova_api +rcvar=nova_api_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-api.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_api_enable:="NO"} +: ${nova_api_logdir:="/var/log/nova"} +: ${nova_api_args:="--log-file ${nova_api_logdir}/nova-api.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-api ${nova_api_args}" + +nova_precmd() { + mkdir -p ${nova_api_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-cells.in b/emulators/py-nova/files/nova-cells.in new file mode 100644 index 000000000000..0e7ecd4da772 --- /dev/null +++ b/emulators/py-nova/files/nova-cells.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_cells +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_cells: +# +# nova_cells_enable="YES" +# +# nova_cells_enable (bool): +# Set it to "YES" to enable nova_cells. +# Default is "NO". +# +# nova_cells_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_cells_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_cells_logdir}/nova-cells.log" +# + +. /etc/rc.subr + +name=nova_cells +rcvar=nova_cells_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-cells.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_cells_enable:="NO"} +: ${nova_cells_logdir:="/var/log/nova"} +: ${nova_cells_args:="--log-file ${nova_cells_logdir}/nova-cells.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-cells ${nova_cells_args}" + +nova_precmd() { + mkdir -p ${nova_cells_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-cert.in b/emulators/py-nova/files/nova-cert.in new file mode 100644 index 000000000000..6c2f17692072 --- /dev/null +++ b/emulators/py-nova/files/nova-cert.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_cert +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_cert: +# +# nova_cert_enable="YES" +# +# nova_cert_enable (bool): +# Set it to "YES" to enable nova_cert. +# Default is "NO". +# +# nova_cert_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_cert_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_cert_logdir}/nova-cert.log" +# + +. /etc/rc.subr + +name=nova_cert +rcvar=nova_cert_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-cert.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_cert_enable:="NO"} +: ${nova_cert_logdir:="/var/log/nova"} +: ${nova_cert_args:="--log-file ${nova_cert_logdir}/nova-cert.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-cert ${nova_cert_args}" + +nova_precmd() { + mkdir -p ${nova_cert_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-compute.conf.sample b/emulators/py-nova/files/nova-compute.conf.sample new file mode 100644 index 000000000000..a6ae707b0407 --- /dev/null +++ b/emulators/py-nova/files/nova-compute.conf.sample @@ -0,0 +1,15 @@ +[DEFAULT] +compute_driver=libvirt.LibvirtDriver +force_raw_images = True +use_cow_images = False + +[libvirt] +virt_type=qemu + +# Force using PHY driver for Xen hypervisor +force_xen_phy=True + +# Disable CPU tracking when using QEMU driver. +# Change this option to True when using Xen driver. +online_cpu_tracking=False + diff --git a/emulators/py-nova/files/nova-compute.in b/emulators/py-nova/files/nova-compute.in new file mode 100644 index 000000000000..921ae615f506 --- /dev/null +++ b/emulators/py-nova/files/nova-compute.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_compute +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_compute: +# +# nova_compute_enable="YES" +# +# nova_compute_enable (bool): +# Set it to "YES" to enable nova_compute. +# Default is "NO". +# +# nova_compute_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_compute_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_compute_logdir}/nova-compute.log" +# + +. /etc/rc.subr + +name=nova_compute +rcvar=nova_compute_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-compute.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_compute_enable:="NO"} +: ${nova_compute_logdir:="/var/log/nova"} +: ${nova_compute_args:="--log-file ${nova_compute_logdir}/nova-compute.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-compute ${nova_compute_args}" + +nova_precmd() { + mkdir -p ${nova_compute_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-conductor.in b/emulators/py-nova/files/nova-conductor.in new file mode 100644 index 000000000000..8b1b7d1568bb --- /dev/null +++ b/emulators/py-nova/files/nova-conductor.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_conductor +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_conductor: +# +# nova_conductor_enable="YES" +# +# nova_conductor_enable (bool): +# Set it to "YES" to enable nova_conductor. +# Default is "NO". +# +# nova_conductor_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_conductor_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_conductor_logdir}/nova-conductor.log" +# + +. /etc/rc.subr + +name=nova_conductor +rcvar=nova_conductor_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-conductor.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_conductor_enable:="NO"} +: ${nova_conductor_logdir:="/var/log/nova"} +: ${nova_conductor_args:="--log-file ${nova_conductor_logdir}/nova-conductor.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-conductor ${nova_conductor_args}" + +nova_precmd() { + mkdir -p ${nova_conductor_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-consoleauth.in b/emulators/py-nova/files/nova-consoleauth.in new file mode 100644 index 000000000000..93b6524ad385 --- /dev/null +++ b/emulators/py-nova/files/nova-consoleauth.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_consoleauth +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_consoleauth: +# +# nova_consoleauth_enable="YES" +# +# nova_consoleauth_enable (bool): +# Set it to "YES" to enable nova_consoleauth. +# Default is "NO". +# +# nova_consoleauth_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_consoleauth_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_consoleauth_logdir}/nova-consoleauth.log" +# + +. /etc/rc.subr + +name=nova_consoleauth +rcvar=nova_consoleauth_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-consoleauth.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_consoleauth_enable:="NO"} +: ${nova_consoleauth_logdir:="/var/log/nova"} +: ${nova_consoleauth_args:="--log-file ${nova_consoleauth_logdir}/nova-consoleauth.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-consoleauth ${nova_consoleauth_args}" + +nova_precmd() { + mkdir -p ${nova_consoleauth_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-network.in b/emulators/py-nova/files/nova-network.in new file mode 100644 index 000000000000..f2e156302d8f --- /dev/null +++ b/emulators/py-nova/files/nova-network.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_network +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_network: +# +# nova_network_enable="YES" +# +# nova_network_enable (bool): +# Set it to "YES" to enable nova_network. +# Default is "NO". +# +# nova_network_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_network_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_network_logdir}/nova-network.log" +# + +. /etc/rc.subr + +name=nova_network +rcvar=nova_network_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-network.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_network_enable:="NO"} +: ${nova_network_logdir:="/var/log/nova"} +: ${nova_network_args:="--log-file ${nova_network_logdir}/nova-network.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-network ${nova_network_args}" + +nova_precmd() { + mkdir -p ${nova_network_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-scheduler.in b/emulators/py-nova/files/nova-scheduler.in new file mode 100644 index 000000000000..240b5ffeb5d7 --- /dev/null +++ b/emulators/py-nova/files/nova-scheduler.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_scheduler +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_scheduler: +# +# nova_scheduler_enable="YES" +# +# nova_scheduler_enable (bool): +# Set it to "YES" to enable nova_scheduler. +# Default is "NO". +# +# nova_scheduler_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_scheduler_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_scheduler_logdir}/nova-scheduler.log" +# + +. /etc/rc.subr + +name=nova_scheduler +rcvar=nova_scheduler_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-scheduler.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_scheduler_enable:="NO"} +: ${nova_scheduler_logdir:="/var/log/nova"} +: ${nova_scheduler_args:="--log-file ${nova_scheduler_logdir}/nova-scheduler.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-scheduler ${nova_scheduler_args}" + +nova_precmd() { + mkdir -p ${nova_scheduler_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova-serialproxy.in b/emulators/py-nova/files/nova-serialproxy.in new file mode 100644 index 000000000000..05247b6a0bbb --- /dev/null +++ b/emulators/py-nova/files/nova-serialproxy.in @@ -0,0 +1,53 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: nova_serialproxy +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# +# Add the following lines to /etc/rc.conf to enable nova_serialproxy: +# +# nova_serialproxy_enable="YES" +# +# nova_serialproxy_enable (bool): +# Set it to "YES" to enable nova_serialproxy. +# Default is "NO". +# +# nova_serialproxy_logdir (str): +# Set it to chagge log directory +# Default is "/var/log/nova" +# +# nova_serialproxy_args (str): +# Set it to change command line arguments. +# Default is "--log-file ${nova_serialproxy_logdir}/nova-serialproxy.log" +# + +. /etc/rc.subr + +name=nova_serialproxy +rcvar=nova_serialproxy_enable + +PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH + +pidfile="/var/run/nova-serialproxy.pid" +procname="%%PREFIX%%/bin/python2.7" + +start_precmd=nova_precmd + +load_rc_config $name + +: ${nova_serialproxy_enable:="NO"} +: ${nova_serialproxy_logdir:="/var/log/nova"} +: ${nova_serialproxy_args:="--log-file ${nova_serialproxy_logdir}/nova-serialproxy.log"} + +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} nova-serialproxy ${nova_serialproxy_args}" + +nova_precmd() { + mkdir -p ${nova_serialproxy_logdir} +} + +run_rc_command "$1" diff --git a/emulators/py-nova/files/nova.conf.sample b/emulators/py-nova/files/nova.conf.sample new file mode 100644 index 000000000000..95dd7ea27424 --- /dev/null +++ b/emulators/py-nova/files/nova.conf.sample @@ -0,0 +1,80 @@ +[DEFAULT] +dhcpbridge_flagfile=/usr/local/etc/nova/nova.conf +dhcpbridge=/usr/local/bin/nova-dhcpbridge +log-dir=/var/log/nova +state_path=/var/lib/nova +force_dhcp_release=False +verbose=True +ec2_private_dns_show_ip=True +enabled_apis=osapi_compute,metadata +rpc_backend = rabbit +auth_strategy = keystone +my_ip = 192.168.1.10 +use_neutron = False +firewall_driver = nova.virt.firewall.NoopFirewallDriver +use_ipv6 = False + +osapi_compute_listen="0.0.0.0" +osapi_compute_listen_port=8774 + +network_driver=nova.network.freebsd_net +libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtGenericVIFDriver +freebsdnet_interface_driver=nova.network.freebsd_net.FreeBSDBridgeInterfaceDriver +l3_lib=nova.network.l3.FreeBSDNetL3 +network_api_class=nova.network.api.API +security_group_api=nova +network_manager=nova.network.manager.FlatDHCPManager +network_size=254 +allow_same_net_traffic=False +multi_host=True +send_arp_for_ha=False +share_dhcp_address=True +# specify nic for public +public_interface=em0 +# specify any name you like for bridge +flat_network_bridge=br100 +flat_interface=tap0 + +[vnc] +enabled = False + +[glance] +api_servers = http://controller:9292 + +[keystone_authtoken] +auth_uri = http://controller:5000 +auth_url = http://controller:35357 +memcached_servers = controller:11211 +auth_type = password +project_domain_name = default +user_domain_name = default +project_name = service +username = nova +password = nova + +[oslo_messaging_rabbit] +rabbit_host = controller +rabbit_userid = openstack +rabbit_password = RABBIT_PASS + +[api_database] +connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova_api + +[database] +connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova + +[oslo_concurrency] +lock_path=/var/lock/nova + +[libvirt] +use_virtio_for_bridges=True + +# add this options when using QEMU +cpu_mode=none + +[wsgi] +api_paste_config=/usr/local/etc/nova/api-paste.ini + +[serial_console] +# Enable serial console when using QEMU driver +enabled=True diff --git a/emulators/py-nova/pkg-descr b/emulators/py-nova/pkg-descr new file mode 100644 index 000000000000..6c6dfe13919c --- /dev/null +++ b/emulators/py-nova/pkg-descr @@ -0,0 +1,5 @@ +OpenStack Nova provides a cloud computing fabric controller, supporting a wide +variety of compute technologies, including: libvirt (KVM, Xen, LXC and more), +Hyper-V, VMware, XenServer and OpenStack Ironic. + +WWW: http://openstack.org/nova diff --git a/emulators/py-nova/pkg-message b/emulators/py-nova/pkg-message new file mode 100644 index 000000000000..560065737653 --- /dev/null +++ b/emulators/py-nova/pkg-message @@ -0,0 +1,47 @@ +Please note that this is a development version of nova. +Many features are not available. + +Currently nova works on FreeBSD 11 and supports QEMU and Xen. + +Common issues: +- Security groups are not implemented +- ARP spoofing, DHCP isolation protection are not implemented +- Nova services work from the root user +- No IPv6 support + +QEMU issues: +- Need to enable serialconsole (TCP) +- Need to disable online CPU tracking +- Cannot mount cinder volumes + +Xen issues: +- Live snapshots doesn't work +- No support for cinder volume hot-plugging +- XENBUS delay (5 min) when using qemu driver and COW images +- Some linux images cannot be booted + +Nova requires procfs to be mounted. +Please add this line to /etc/fstab: +proc /proc procfs rw 0 0 + +Also devel/libvirt port should be installed with enabled QEMU +backend or qemu tools installed separately. + +Directory to keep VM data should be created manually +# su -m nova -c "mkdir /var/lib/nova/instances" + +For proper networking enable PF +# sysrc pf_enable="YES" +# sysrc pflog_enable="YES" +# sysrc gateway_enable="YES" + +/etc/pf.conf should contain: +rdr-anchor "org.openstack/*" +nat-anchor "org.openstack/*" +anchor "org.openstack/*" + +To boot images on Xen please specify glance metadata properties +glance image-update b1216ff6-23ec-4a08-baee-43994760158a \ + --property hypervisor_type=xen \ + --property vm_mode=hvm \ + --property hw_disk_bus=xen diff --git a/emulators/py-nova/pkg-plist b/emulators/py-nova/pkg-plist new file mode 100644 index 000000000000..9a5098a03183 --- /dev/null +++ b/emulators/py-nova/pkg-plist @@ -0,0 +1,18 @@ +@owner nova +@dir %%ETCDIR%% +%%ETCDIR%%/release.sample +@sample %%ETCDIR%%/nova.conf.sample +@sample %%ETCDIR%%/nova-compute.conf.sample +@sample %%ETCDIR%%/logging.conf.sample +%%ETCDIR%%/README-nova.conf.txt +%%ETCDIR%%/api-paste.ini +%%ETCDIR%%/cells.json +@sample %%ETCDIR%%/nova-config-generator.conf.sample +@sample %%ETCDIR%%/nova-policy-generator.conf.sample +%%ETCDIR%%/policy.json +@owner root +@sample %%ETCDIR%%/rootwrap.conf.sample +@dir %%ETCDIR%%/rootwrap.d +%%ETCDIR%%/rootwrap.d/api-metadata.filters +%%ETCDIR%%/rootwrap.d/compute.filters +%%ETCDIR%%/rootwrap.d/network.filters |