self._arguments.update(new_arguments)
self.update_parser()
+ def _parse_required_arguments(self, required, parsed_args):
+ if not required:
+ return True
+ if isinstance(required, tuple):
+ for item in required:
+ if not self._parse_required_arguments(item, parsed_args):
+ return False
+ return True
+ if isinstance(required, list):
+ for item in required:
+ if self._parse_required_arguments(item, parsed_args):
+ return True
+ return False
+ return required in parsed_args
+
def parse(self, new_args=None):
"""Parse user input"""
try:
pkargs = (new_args,) if new_args else ()
self._parsed, unparsed = self.parser.parse_known_args(*pkargs)
- pdict = vars(self._parsed)
- diff = set(self.required or []).difference(
- [k for k in pdict if pdict[k] not in (None, )])
- if diff:
+ parsed_args = [
+ k for k, v in vars(self._parsed).items() if v not in (None, )]
+ if not self._parse_required_arguments(self.required, parsed_args):
self.print_help()
- miss = ['/'.join(self.arguments[k].parsed_name) for k in diff]
- raise CLISyntaxError(
- 'Missing required arguments (%s)' % ', '.join(miss))
+ raise CLISyntaxError('Missing required arguments')
+
except SystemExit:
raiseCLIError(CLISyntaxError('Argument Syntax Error'))
for name, arg in self.arguments.items():
from kamaki.cli.errors import (
raiseCLIError, CLISyntaxError, CLIBaseUrlError, CLIInvalidArgument)
from kamaki.clients.cyclades import CycladesClient, ClientError
-from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
-from kamaki.cli.argument import ProgressBarArgument, DateArgument, IntArgument
+from kamaki.cli.argument import (
+ FlagArgument, ValueArgument, KeyValueArgument, RepeatableArgument,
+ ProgressBarArgument, DateArgument, IntArgument)
from kamaki.cli.commands import _command_init, errors, addLogSettings
from kamaki.cli.commands import (
_optional_output_cmd, _optional_json, _name_filter, _id_filter)
image_id=self['image_id'])
+class FirewallProfileArgument(ValueArgument):
+
+ profiles = ('DISABLED', 'ENABLED', 'PROTECTED')
+
+ @property
+ def value(self):
+ return getattr(self, '_value', None)
+
+ @value.setter
+ def value(self, new_profile):
+ if new_profile:
+ new_profile = new_profile.upper()
+ if new_profile in self.profiles:
+ self._value = new_profile
+ else:
+ raise CLIInvalidArgument(
+ 'Invalid firewall profile %s' % new_profile,
+ details=['Valid values: %s' % ', '.join(self.profiles)])
+
+
@command(server_cmds)
class server_modify(_init_cyclades, _optional_output_cmd):
"""Modify attributes of a virtual server"""
arguments = dict(
server_name=ValueArgument('The new name', '--name'),
flavor_id=IntArgument('Set a different flavor', '--flavor-id'),
+ firewall_profile=FirewallProfileArgument(
+ 'Valid values: %s' % (', '.join(FirewallProfileArgument.profiles)),
+ '--firewall'),
+ metadata_to_set=KeyValueArgument(
+ 'Set metadata in key=value form (can be repeated)',
+ '--set-metadata'),
+ metadata_to_delete=RepeatableArgument(
+ 'Delete metadata by key (can be repeated)', '--del-metadata')
)
- required = ['server_name', 'flavor_id']
+ required = [
+ 'server_name', 'flavor_id', 'firewall_profile', 'metadata_to_set',
+ 'metadata_to_del']
@errors.generic.all
@errors.cyclades.connection
self.client.update_server_name((server_id), self['server_name'])
if self['flavor_id']:
self.client.resize_server(server_id, self['flavor_id'])
+ if self['firewall_profile']:
+ self.client.set_firewall_profile(
+ server_id=server_id, profile=self['firewall_profile'])
+ if self['metadata_to_set']:
+ self.client.update_server_metadata(
+ server_id, **self['metadata_to_set'])
+ for key in self['metadata_to_delete']:
+ errors.cyclades.metadata(
+ self.client.delete_server_metadata)(server_id, key=key)
if self['with_output']:
self._optional_output(self.client.get_server_details(server_id))
@command(server_cmds)
-class server_firewall(_init_cyclades):
- """Manage virtual server firewall profiles for public networks"""
-
-
-@command(server_cmds)
-class server_firewall_set(
- _init_cyclades, _optional_output_cmd, _firewall_wait):
- """Set the firewall profile on virtual server public network
- Values for profile:
- - DISABLED: Shutdown firewall
- - ENABLED: Firewall in normal mode
- - PROTECTED: Firewall in secure mode
- """
-
- arguments = dict(
- wait=FlagArgument('Wait server firewall to build', ('-w', '--wait')),
- timeout=IntArgument(
- 'Set wait timeout in seconds (default: 60)', '--timeout',
- default=60)
- )
-
- @errors.generic.all
- @errors.cyclades.connection
- @errors.cyclades.server_id
- @errors.cyclades.firewall
- def _run(self, server_id, profile):
- if self['timeout'] and not self['wait']:
- raise CLIInvalidArgument('Invalid use of --timeout', details=[
- 'Timeout is used only along with -w/--wait'])
- old_profile = self.client.get_firewall_profile(server_id)
- if old_profile.lower() == profile.lower():
- self.error('Firewall of server %s: allready in status %s' % (
- server_id, old_profile))
- else:
- self._optional_output(self.client.set_firewall_profile(
- server_id=int(server_id), profile=('%s' % profile).upper()))
- if self['wait']:
- self._wait(server_id, old_profile, timeout=self['timeout'])
-
- def main(self, server_id, profile):
- super(self.__class__, self)._run()
- self._run(server_id=server_id, profile=profile)
-
-
-@command(server_cmds)
-class server_firewall_get(_init_cyclades):
- """Get the firewall profile for a virtual servers' public network"""
-
- @errors.generic.all
- @errors.cyclades.connection
- @errors.cyclades.server_id
- def _run(self, server_id):
- self.writeln(self.client.get_firewall_profile(server_id))
-
- def main(self, server_id):
- super(self.__class__, self)._run()
- self._run(server_id=server_id)
-
-
-@command(server_cmds)
class server_addr(_init_cyclades, _optional_json):
"""List the addresses of all network interfaces on a virtual server"""
@command(server_cmds)
-class server_metadata(_init_cyclades):
- """Manage Server metadata (key:value pairs of server attributes)"""
-
-
-@command(server_cmds)
class server_metadata_list(_init_cyclades, _optional_json):
"""Get server metadata"""