Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*.swo
*.swp
*~
otcextensions-*/
.coverage
.idea
.stestr/
Expand Down
201 changes: 38 additions & 163 deletions otcextensions/osclient/rds/v3/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,15 @@ def get_parser(self, prog_name):
help=_("Name of the instance.")
)
parser.add_argument(
'flavor_ref',
metavar='<flavor_ref>',
'flavor',
metavar='<flavor>',
help=_("Flavor spec_code")
)
disk_group = parser.add_argument_group('Disk data')
disk_group.add_argument(
'--size',
metavar='<size>',
dest='volume_size',
type=int,
required=True,
help=_("Size of the instance disk volume in GB. ")
Expand All @@ -196,6 +197,7 @@ def get_parser(self, prog_name):
metavar='{' + ','.join(DISK_TYPE_CHOICES) + '}',
type=lambda s: s.upper(),
required=True,
dest='volume_type',
choices=[s.upper() for s in DISK_TYPE_CHOICES],
help=_("Volume type. (COMMON, ULTRAHIGH).")
)
Expand Down Expand Up @@ -224,7 +226,7 @@ def get_parser(self, prog_name):
)
parser.add_argument(
'--configuration',
dest='configuration_id',
dest='configuration',
metavar='<configuration_id>',
default=None,
help=_("ID of the configuration group to attach to the instance.")
Expand Down Expand Up @@ -253,16 +255,18 @@ def get_parser(self, prog_name):
new_instance_group.add_argument(
'--router-id',
metavar='<router_id>',
dest='router',
help=_('ID of a Router the DB should be connected to')
)
new_instance_group.add_argument(
'--network-id',
metavar='<net_id>',
dest='network',
help=_('ID of a Neutron network the DB should be connected to.')
)
new_instance_group.add_argument(
'--security-group-id',
dest='security_group_id',
dest='security_group',
metavar='<security_group_id>',
help=_('Security group ID')
)
Expand Down Expand Up @@ -301,6 +305,17 @@ def get_parser(self, prog_name):
metavar='<backup>',
help=_('Backup ID or Name to create new instance from.')
)
create_from_group.add_argument(
'--backup-keepdays',
metavar='<backup_keepday>',
help=_('Specifies the retention days for specific backup files.')
)
create_from_group.add_argument(
'--backup-timeframe',
metavar='<HH:MM-HH:MM>',
help=_('Specifies the backup time window. Automated backups will '
'be triggered during the backup time window.')
)
create_from_group.add_argument(
'--restore-time',
metavar='<time>',
Expand All @@ -321,166 +336,26 @@ def get_parser(self, prog_name):

def take_action(self, parsed_args):
# Attention: not conform password result in BadRequest with no info
client = self.app.client_manager.rds

client = self.app.client_manager
attrs = {}
args_list = [
'name', 'availability_zone', 'configuration_id', 'region',
'router_id', 'network_id', 'security_group_id',
'disk_encryption_id', 'port', 'password', 'flavor_ref'
]
for arg in args_list:
if getattr(parsed_args, arg):
attrs[arg] = getattr(parsed_args, arg)
volume = {}
if parsed_args.size:
volume = {"size": parsed_args.size}
if parsed_args.volume_type:
volume['type'] = parsed_args.volume_type
attrs['volume'] = volume
if parsed_args.datastore_type:
datastore = {
'type': parsed_args.datastore_type,
'version': parsed_args.datastore_version
}
attrs['datastore'] = datastore
if parsed_args.ha_mode:
ha = {'mode': 'ha', 'replication_mode': parsed_args.ha_mode}
attrs['ha'] = ha
if parsed_args.charge_mode:
attrs['charge_info'] = {'charge_mode': parsed_args.charge_mode}

new_instance_required = [
parsed_args.router_id,
parsed_args.network_id,
parsed_args.security_group_id,
parsed_args.password
]

if (not parsed_args.replica_of
and not (parsed_args.datastore_type
and parsed_args.datastore_version)):
raise exceptions.CommandError(
_('`--datastore-type` and `--datastore-version` are '
'required')
)

if parsed_args.replica_of:
# Create replica
if (parsed_args.password or parsed_args.port
or parsed_args.router_id or parsed_args.security_group_id
or parsed_args.network_id):
raise exceptions.CommandError(
_('Setting password/port/router/network/sg is not '
'supported when creating replica')
)
src = client.find_instance(parsed_args.replica_of,
ignore_missing=False)
parsed_args.datastore_type = src['datastore']['type']
parsed_args.datastore_version = src['datastore']['version']
attrs['replica_of_id'] = src.id
attrs.pop('datastore', None)
elif parsed_args.from_instance:
source = client.find_instance(parsed_args.from_instance,
ignore_missing=False)
if parsed_args.backup:
# Create from backup
backup = client.find_backup(
name_or_id=parsed_args.backup,
instance=source,
ignore_missing=False)
attrs['restore_point'] = {
'type': 'backup',
'backup_id': backup.id,
'instance_id': backup.instance_id
}
elif parsed_args.restore_time:
attrs['restore_point'] = {
'type': 'timestamp',
'restore_time': parsed_args.restore_time,
'instance_id': source.id
}
elif parsed_args.backup or parsed_args.restore_time:
raise exceptions.CommandError(
_('`--from-instance` is required when restoring from '
'backup or using PITR.')
)
elif not all(new_instance_required):
raise exceptions.CommandError(
_('`--router-id`, `--subnet-id`, `--security-group-id`, '
'`--password` parameters are required when creating '
'new primary instance.')
)

flavors = list(client.flavors(
datastore_name=parsed_args.datastore_type,
version_name=parsed_args.datastore_version)
)
flavor = None
for f in flavors:
if f.name == parsed_args.flavor_ref:
flavor = f
if not flavor:
raise exceptions.CommandError(
_(
'Flavor {flavor} can not be found'.format(
flavor=parsed_args.flavor_ref)
)
)
if flavor.instance_mode == 'ha' and not parsed_args.ha_mode:
raise exceptions.CommandError(
_('`--ha-mode` is required when using HA enabled flavor')
)
if flavor.instance_mode != 'ha' and parsed_args.ha_mode:
raise exceptions.CommandError(
_('`ha` enabled flavor must be '
'chosen when setting ha_mode')
)
if flavor.instance_mode != 'replica' and parsed_args.replica_of:
raise exceptions.CommandError(
_('`replica` enabled flavor must be '
'chosen when creating replica')
)
if parsed_args.ha_mode:
if ',' not in parsed_args.availability_zone:
raise exceptions.CommandError(
_('List of availability zones must be used when '
'creating ha instance')
)
if parsed_args.ha_mode:
mode = parsed_args.ha_mode
if (parsed_args.datastore_type.lower() == 'postgresql'
and mode not in ['async', 'sync']):
raise exceptions.CommandError(
_('`async` or `sync` ha_mode can be used for '
'PostgreSQL isntance')
)
elif (parsed_args.datastore_type.lower() == 'mysql'
and mode not in ['async', 'semisync']):
raise exceptions.CommandError(
_('`async` or `semisync` ha_mode can be used for '
'MySQL isntance')
)
elif (parsed_args.datastore_type.lower() == 'sqlserver'
and mode not in ['sync']):
raise exceptions.CommandError(
_('Only `sync` ha_mode can be used for '
'SQLServer isntance')
)
if parsed_args.wait_interval and not parsed_args.wait:
raise exceptions.CommandError(
_('`--wait-interval` is only valid with `--wait`')
)

obj = client.create_instance(**attrs)

if obj.job_id and parsed_args.wait:
wait_args = {}
if parsed_args.wait_interval:
wait_args['interval'] = parsed_args.wait_interval

client.wait_for_job(obj.job_id, **wait_args)
obj = client.get_instance(obj.id)
for attr in [
'availability_zone', 'backup', 'backup_keepdays',
'backup_timeframe', 'charge_mode', 'configuration',
'datastore_type', 'datastore_version', 'disk_encryption_id',
'flavor', 'from_instance', 'ha_mode', 'name', 'network',
'password', 'port', 'region', 'replica_of', 'restore_time',
'router', 'security_group', 'volume_size', 'volume_type', 'wait',
'wait_interval'
]:
if getattr(parsed_args, attr):
attrs[attr] = getattr(parsed_args, attr)

if not parsed_args.wait:
attrs['wait'] = False

obj = client.create_rds_instance(
**attrs
)

display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters={})
Expand Down
14 changes: 12 additions & 2 deletions otcextensions/sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from otcextensions.sdk.compute.v2 import server
from otcextensions.common import exc

from otcextensions.sdk.cloud import rds as _rds


_logger = _log.setup_logging('openstack')

Expand Down Expand Up @@ -127,9 +129,8 @@
},
'rds': {
'service_type': 'rds',
# 'additional_headers': {'content-type': 'application/json'},
'endpoint_service_type': 'rdsv3',
'append_project_id': True,
'append_project_id': True
},
'sdrs': {
'service_type': 'sdrs'
Expand Down Expand Up @@ -243,6 +244,13 @@ def get_ak_sk(conn):
return(ak, sk)


def extend_instance(obj, cls):
"""Apply mixins to a class instance after creation"""
base_cls = obj.__class__
base_cls_name = obj.__class__.__name__
obj.__class__ = type(base_cls_name, (base_cls, cls), {})


def patch_openstack_resources():
openstack.compute.v2.server.Server._get_tag_struct = \
server.Server._get_tag_struct
Expand Down Expand Up @@ -310,6 +318,8 @@ def load(conn, **kwargs):

patch_openstack_resources()

extend_instance(conn, _rds.RdsMixin)

return None


Expand Down
Empty file.
Loading