ec2-api/ec2api/api/dhcp_options.py

188 lines
6.8 KiB
Python

# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import netaddr
from oslo.config import cfg
from ec2api.api import clients
from ec2api.api import common
from ec2api.api import ec2utils
from ec2api.db import api as db_api
from ec2api import exception
from ec2api.openstack.common.gettextutils import _
from ec2api.openstack.common import log as logging
LOG = logging.getLogger(__name__)
ec2_opts = [
cfg.IntOpt('network_device_mtu',
default=1500,
help='MTU size to set by DHCP for instances. Corresponds '
'with the network_device_mtu in ec2api.conf.')
]
CONF = cfg.CONF
CONF.register_opts(ec2_opts)
"""DHCP options related API implementation
"""
class Validator(common.Validator):
def dopt_id_or_default(self, id):
if id == 'default':
return
self.ec2_id(id, ['dopt'])
DHCP_OPTIONS_MAP = {'domain-name-servers': 'dns-server',
'domain-name': 'domain-name',
'ntp-servers': 'ntp-server',
'netbios-name-servers': 'netbios-ns',
'netbios-node-type': 'netbios-nodetype'}
def create_dhcp_options(context, dhcp_configuration):
dhcp_options = {}
for dhcp_option in dhcp_configuration:
key = dhcp_option['key']
values = dhcp_option['value']
if key not in DHCP_OPTIONS_MAP:
raise exception.InvalidParameterValue(
value=values,
parameter=key,
reason='Unrecognized key is specified')
if not type(values) is list:
raise exception.InvalidParameterValue(
value=values,
parameter=key,
reason='List of values is expected')
if key not in ['domain-name', 'netbios-node-type']:
ips = []
for ip in values:
ip_address = netaddr.IPAddress(ip)
if not ip_address:
raise exception.InvalidParameterValue(
value=ip,
parameter=key,
reason='Invalid list of IPs is specified')
ips.append(ip)
dhcp_options[key] = ips
else:
dhcp_options[key] = values
dhcp_options = db_api.add_item(context, 'dopt',
{'dhcp_configuration': dhcp_options})
return {'dhcpOptions':
_format_dhcp_options(context, dhcp_options)}
def delete_dhcp_options(context, dhcp_options_id):
if not dhcp_options_id:
raise exception.MissingParameter(
_('DHCP options ID must be specified'))
dhcp_options = ec2utils.get_db_item(context, 'dopt',
dhcp_options_id)
vpcs = db_api.get_items(context, 'vpc')
for vpc in vpcs:
if dhcp_options['id'] == vpc.get('dhcp_options_id'):
raise exception.DependencyViolation(
obj1_id=dhcp_options['id'],
obj2_id=vpc['id'])
db_api.delete_item(context, dhcp_options['id'])
return True
class DhcpOptionsDescriber(common.TaggableItemsDescriber,
common.NonOpenstackItemsDescriber):
KIND = 'dopt'
FILTER_MAP = {'dhcp_options_id': 'dhcpOptionsId',
'key': ['dhcpConfigurationSet', 'key']}
def format(self, dhcp_options):
return _format_dhcp_options(self.context, dhcp_options)
def describe_dhcp_options(context, dhcp_options_id=None,
filter=None):
formatted_dhcp_options = DhcpOptionsDescriber().describe(
context, ids=dhcp_options_id, filter=filter)
return {'dhcpOptionsSet': formatted_dhcp_options}
def associate_dhcp_options(context, dhcp_options_id, vpc_id):
vpc = ec2utils.get_db_item(context, 'vpc', vpc_id)
rollback_dhcp_options_id = vpc.get('dhcp_options_id')
if dhcp_options_id == 'default':
dhcp_options_id = None
dhcp_options = None
else:
dhcp_options = ec2utils.get_db_item(context, 'dopt', dhcp_options_id)
dhcp_options_id = dhcp_options['id']
neutron = clients.neutron(context)
os_ports = neutron.list_ports()['ports']
network_interfaces = db_api.get_items(context, 'eni')
rollback_dhcp_options_object = (
db_api.get_item_by_id(context, 'dopt', rollback_dhcp_options_id)
if dhcp_options_id is not None else
None)
with common.OnCrashCleaner() as cleaner:
_associate_vpc_item(context, vpc, dhcp_options_id)
cleaner.addCleanup(_associate_vpc_item, context, vpc,
rollback_dhcp_options_id)
for network_interface in network_interfaces:
os_port = next((p for p in os_ports
if p['id'] == network_interface['os_id']), None)
if not os_port:
continue
_add_dhcp_opts_to_port(context, dhcp_options,
network_interface, os_port, neutron)
cleaner.addCleanup(_add_dhcp_opts_to_port, context,
rollback_dhcp_options_object, network_interface,
os_port, neutron)
return True
def _add_dhcp_opts_to_port(context, dhcp_options, network_interface, os_port,
neutron=None):
dhcp_opts = [{'opt_name': 'mtu',
'opt_value': str(CONF.network_device_mtu)}]
if dhcp_options is not None:
for key, values in dhcp_options['dhcp_configuration'].items():
strvalues = [str(v) for v in values]
dhcp_opts.append({'opt_name': DHCP_OPTIONS_MAP[key],
'opt_value': ','.join(strvalues)})
if not neutron:
neutron = clients.neutron(context)
neutron.update_port(os_port['id'],
{'port': {'extra_dhcp_opts': dhcp_opts}})
def _format_dhcp_options(context, dhcp_options):
dhcp_configuration = []
for key, values in dhcp_options['dhcp_configuration'].items():
items = [{'value': v} for v in values]
dhcp_configuration.append({'key': key, 'valueSet': items})
return {'dhcpOptionsId': dhcp_options['id'],
'dhcpConfigurationSet': dhcp_configuration}
def _associate_vpc_item(context, vpc, dhcp_options_id):
vpc['dhcp_options_id'] = dhcp_options_id
db_api.update_item(context, vpc)