Revision 264a13f7 kamaki/cli/commands/cyclades.py
b/kamaki/cli/commands/cyclades.py | ||
---|---|---|
371 | 371 |
'%s' % ve]) |
372 | 372 |
|
373 | 373 |
|
374 |
class NetworkIpArgument(RepeatableArgument): |
|
375 |
|
|
376 |
@property |
|
377 |
def value(self): |
|
378 |
return getattr(self, '_value', []) |
|
379 |
|
|
380 |
@value.setter |
|
381 |
def value(self, new_value): |
|
382 |
for v in (new_value or []): |
|
383 |
net_and_ip = v.split(',') |
|
384 |
if len(net_and_ip) < 2: |
|
385 |
raise CLIInvalidArgument( |
|
386 |
'Value "%s" is missing parts' % v, |
|
387 |
details=['Correct format: %s NETWORK_ID,IP' % ( |
|
388 |
self.parsed_name[0])]) |
|
389 |
self._value = getattr(self, '_value', list()) |
|
390 |
self._value.append( |
|
391 |
dict(network=net_and_ip[0], fixed_ip=net_and_ip[1])) |
|
392 |
|
|
393 |
|
|
374 | 394 |
@command(server_cmds) |
375 | 395 |
class server_create(_init_cyclades, _optional_json, _server_wait): |
376 | 396 |
"""Create a server (aka Virtual Machine)""" |
... | ... | |
386 | 406 |
'Create a cluster of servers of this size. In this case, the name' |
387 | 407 |
'parameter is the prefix of each server in the cluster (e.g.,' |
388 | 408 |
'srv1, srv2, etc.', |
389 |
'--cluster-size') |
|
409 |
'--cluster-size'), |
|
410 |
network_id=RepeatableArgument( |
|
411 |
'Connect server to network (can be repeated)', '--network'), |
|
412 |
network_id_and_ip=NetworkIpArgument( |
|
413 |
'Connect server to network w. floating ip ( NETWORK_ID,IP )' |
|
414 |
'(can be repeated)', |
|
415 |
'--network-with-ip'), |
|
390 | 416 |
) |
391 | 417 |
required = ('server_name', 'flavor_id', 'image_id') |
392 | 418 |
|
393 | 419 |
@errors.cyclades.cluster_size |
394 | 420 |
def _create_cluster(self, prefix, flavor_id, image_id, size): |
421 |
networks = [dict(network=netid) for netid in ( |
|
422 |
self['network_id'] or [])] + (self['network_id_and_ip'] or []) |
|
395 | 423 |
servers = [dict( |
396 | 424 |
name='%s%s' % (prefix, i if size > 1 else ''), |
397 | 425 |
flavor_id=flavor_id, |
398 | 426 |
image_id=image_id, |
399 |
personality=self['personality']) for i in range(1, 1 + size)] |
|
427 |
personality=self['personality'], |
|
428 |
networks=networks) for i in range(1, 1 + size)] |
|
400 | 429 |
if size == 1: |
401 | 430 |
return [self.client.create_server(**servers[0])] |
402 | 431 |
try: |
... | ... | |
836 | 865 |
|
837 | 866 |
|
838 | 867 |
@command(network_cmds) |
839 |
class network_info(_init_cyclades, _optional_json): |
|
840 |
"""Detailed information on a network |
|
841 |
To get a list of available networks and network ids, try /network list |
|
842 |
""" |
|
843 |
|
|
844 |
@errors.generic.all |
|
845 |
@errors.cyclades.connection |
|
846 |
@errors.cyclades.network_id |
|
847 |
def _run(self, network_id): |
|
848 |
network = self.client.get_network_details(int(network_id)) |
|
849 |
_add_name(self, network) |
|
850 |
self._print(network, self.print_dict, exclude=('id')) |
|
851 |
|
|
852 |
def main(self, network_id): |
|
853 |
super(self.__class__, self)._run() |
|
854 |
self._run(network_id=network_id) |
|
855 |
|
|
856 |
|
|
857 |
@command(network_cmds) |
|
858 |
class network_list(_init_cyclades, _optional_json, _name_filter, _id_filter): |
|
859 |
"""List networks""" |
|
860 |
|
|
861 |
PERMANENTS = ('id', 'name') |
|
862 |
|
|
863 |
arguments = dict( |
|
864 |
detail=FlagArgument('show detailed output', ('-l', '--details')), |
|
865 |
limit=IntArgument('limit # of listed networks', ('-n', '--number')), |
|
866 |
more=FlagArgument( |
|
867 |
'output results in pages (-n to set items per page, default 10)', |
|
868 |
'--more'), |
|
869 |
enum=FlagArgument('Enumerate results', '--enumerate'), |
|
870 |
status=ValueArgument('filter by status', ('--status')), |
|
871 |
public=FlagArgument('only public networks', ('--public')), |
|
872 |
private=FlagArgument('only private networks', ('--private')), |
|
873 |
dhcp=FlagArgument('show networks with dhcp', ('--with-dhcp')), |
|
874 |
no_dhcp=FlagArgument('show networks without dhcp', ('--without-dhcp')), |
|
875 |
user_id=ValueArgument('filter by user id', ('--user-id')), |
|
876 |
user_name=ValueArgument('filter by user name', ('--user-name')), |
|
877 |
gateway=ValueArgument('filter by gateway (IPv4)', ('--gateway')), |
|
878 |
gateway6=ValueArgument('filter by gateway (IPv6)', ('--gateway6')), |
|
879 |
cidr=ValueArgument('filter by cidr (IPv4)', ('--cidr')), |
|
880 |
cidr6=ValueArgument('filter by cidr (IPv6)', ('--cidr6')), |
|
881 |
type=ValueArgument('filter by type', ('--type')), |
|
882 |
) |
|
883 |
|
|
884 |
def _apply_common_filters(self, networks): |
|
885 |
common_filter = dict() |
|
886 |
if self['public']: |
|
887 |
if self['private']: |
|
888 |
return [] |
|
889 |
common_filter['public'] = self['public'] |
|
890 |
elif self['private']: |
|
891 |
common_filter['public'] = False |
|
892 |
if self['dhcp']: |
|
893 |
if self['no_dhcp']: |
|
894 |
return [] |
|
895 |
common_filter['dhcp'] = True |
|
896 |
elif self['no_dhcp']: |
|
897 |
common_filter['dhcp'] = False |
|
898 |
if self['user_id'] or self['user_name']: |
|
899 |
uuid = self['user_id'] or self._username2uuid(self['user_name']) |
|
900 |
common_filter['user_id'] = uuid |
|
901 |
for term in ('status', 'gateway', 'gateway6', 'cidr', 'cidr6', 'type'): |
|
902 |
if self[term]: |
|
903 |
common_filter[term] = self[term] |
|
904 |
return filter_dicts_by_dict(networks, common_filter) |
|
905 |
|
|
906 |
def _add_name(self, networks, key='user_id'): |
|
907 |
uuids = self._uuids2usernames( |
|
908 |
list(set([net[key] for net in networks]))) |
|
909 |
for net in networks: |
|
910 |
v = net.get(key, None) |
|
911 |
if v: |
|
912 |
net[key] += ' (%s)' % uuids[v] |
|
913 |
return networks |
|
914 |
|
|
915 |
@errors.generic.all |
|
916 |
@errors.cyclades.connection |
|
917 |
def _run(self): |
|
918 |
withcommons = False |
|
919 |
for term in ( |
|
920 |
'status', 'public', 'private', 'user_id', 'user_name', 'type', |
|
921 |
'gateway', 'gateway6', 'cidr', 'cidr6', 'dhcp', 'no_dhcp'): |
|
922 |
if self[term]: |
|
923 |
withcommons = True |
|
924 |
break |
|
925 |
detail = self['detail'] or withcommons |
|
926 |
networks = self.client.list_networks(detail) |
|
927 |
networks = self._filter_by_name(networks) |
|
928 |
networks = self._filter_by_id(networks) |
|
929 |
if withcommons: |
|
930 |
networks = self._apply_common_filters(networks) |
|
931 |
if not (self['detail'] or ( |
|
932 |
self['json_output'] or self['output_format'])): |
|
933 |
remove_from_items(networks, 'links') |
|
934 |
if detail and not self['detail']: |
|
935 |
for net in networks: |
|
936 |
for key in set(net).difference(self.PERMANENTS): |
|
937 |
net.pop(key) |
|
938 |
if self['detail'] and not ( |
|
939 |
self['json_output'] or self['output_format']): |
|
940 |
self._add_name(networks) |
|
941 |
self._add_name(networks, 'tenant_id') |
|
942 |
kwargs = dict(with_enumeration=self['enum']) |
|
943 |
if self['more']: |
|
944 |
kwargs['out'] = StringIO() |
|
945 |
kwargs['title'] = () |
|
946 |
if self['limit']: |
|
947 |
networks = networks[:self['limit']] |
|
948 |
self._print(networks, **kwargs) |
|
949 |
if self['more']: |
|
950 |
pager(kwargs['out'].getvalue()) |
|
951 |
|
|
952 |
def main(self): |
|
953 |
super(self.__class__, self)._run() |
|
954 |
self._run() |
|
955 |
|
|
956 |
|
|
957 |
@command(network_cmds) |
|
958 |
class network_create(_init_cyclades, _optional_json, _network_wait): |
|
959 |
"""Create an (unconnected) network""" |
|
960 |
|
|
961 |
arguments = dict( |
|
962 |
cidr=ValueArgument('explicitly set cidr', '--with-cidr'), |
|
963 |
gateway=ValueArgument('explicitly set gateway', '--with-gateway'), |
|
964 |
dhcp=FlagArgument('Use dhcp (default: off)', '--with-dhcp'), |
|
965 |
type=ValueArgument( |
|
966 |
'Valid network types are ' |
|
967 |
'CUSTOM, IP_LESS_ROUTED, MAC_FILTERED (default), PHYSICAL_VLAN', |
|
968 |
'--with-type', |
|
969 |
default='MAC_FILTERED'), |
|
970 |
wait=FlagArgument('Wait network to build', ('-w', '--wait')) |
|
971 |
) |
|
972 |
|
|
973 |
@errors.generic.all |
|
974 |
@errors.cyclades.connection |
|
975 |
@errors.cyclades.network_max |
|
976 |
def _run(self, name): |
|
977 |
r = self.client.create_network( |
|
978 |
name, |
|
979 |
cidr=self['cidr'], |
|
980 |
gateway=self['gateway'], |
|
981 |
dhcp=self['dhcp'], |
|
982 |
type=self['type']) |
|
983 |
_add_name(self, r) |
|
984 |
self._print(r, self.print_dict) |
|
985 |
if self['wait'] and r['status'] in ('PENDING', ): |
|
986 |
self._wait(r['id'], 'PENDING') |
|
987 |
|
|
988 |
def main(self, name): |
|
989 |
super(self.__class__, self)._run() |
|
990 |
self._run(name) |
|
991 |
|
|
992 |
|
|
993 |
@command(network_cmds) |
|
994 |
class network_rename(_init_cyclades, _optional_output_cmd): |
|
995 |
"""Set the name of a network""" |
|
996 |
|
|
997 |
@errors.generic.all |
|
998 |
@errors.cyclades.connection |
|
999 |
@errors.cyclades.network_id |
|
1000 |
def _run(self, network_id, new_name): |
|
1001 |
self._optional_output( |
|
1002 |
self.client.update_network_name(int(network_id), new_name)) |
|
1003 |
|
|
1004 |
def main(self, network_id, new_name): |
|
1005 |
super(self.__class__, self)._run() |
|
1006 |
self._run(network_id=network_id, new_name=new_name) |
|
1007 |
|
|
1008 |
|
|
1009 |
@command(network_cmds) |
|
1010 |
class network_delete(_init_cyclades, _optional_output_cmd, _network_wait): |
|
1011 |
"""Delete a network""" |
|
1012 |
|
|
1013 |
arguments = dict( |
|
1014 |
wait=FlagArgument('Wait network to build', ('-w', '--wait')) |
|
1015 |
) |
|
1016 |
|
|
1017 |
@errors.generic.all |
|
1018 |
@errors.cyclades.connection |
|
1019 |
@errors.cyclades.network_in_use |
|
1020 |
@errors.cyclades.network_id |
|
1021 |
def _run(self, network_id): |
|
1022 |
status = 'DELETED' |
|
1023 |
if self['wait']: |
|
1024 |
r = self.client.get_network_details(network_id) |
|
1025 |
status = r['status'] |
|
1026 |
if status in ('DELETED', ): |
|
1027 |
return |
|
1028 |
|
|
1029 |
r = self.client.delete_network(int(network_id)) |
|
1030 |
self._optional_output(r) |
|
1031 |
|
|
1032 |
if self['wait']: |
|
1033 |
self._wait(network_id, status) |
|
1034 |
|
|
1035 |
def main(self, network_id): |
|
1036 |
super(self.__class__, self)._run() |
|
1037 |
self._run(network_id=network_id) |
|
1038 |
|
|
1039 |
|
|
1040 |
@command(network_cmds) |
|
1041 |
class network_connect(_init_cyclades, _optional_output_cmd): |
|
1042 |
"""Connect a server to a network""" |
|
1043 |
|
|
1044 |
@errors.generic.all |
|
1045 |
@errors.cyclades.connection |
|
1046 |
@errors.cyclades.server_id |
|
1047 |
@errors.cyclades.network_id |
|
1048 |
def _run(self, server_id, network_id): |
|
1049 |
self._optional_output( |
|
1050 |
self.client.connect_server(int(server_id), int(network_id))) |
|
1051 |
|
|
1052 |
def main(self, server_id, network_id): |
|
1053 |
super(self.__class__, self)._run() |
|
1054 |
self._run(server_id=server_id, network_id=network_id) |
|
1055 |
|
|
1056 |
|
|
1057 |
@command(network_cmds) |
|
1058 |
class network_disconnect(_init_cyclades): |
|
1059 |
"""Disconnect a nic that connects a server to a network |
|
1060 |
Nic ids are listed as "attachments" in detailed network information |
|
1061 |
To get detailed network information: /network info <network id> |
|
1062 |
""" |
|
1063 |
|
|
1064 |
@errors.cyclades.nic_format |
|
1065 |
def _server_id_from_nic(self, nic_id): |
|
1066 |
return nic_id.split('-')[1] |
|
1067 |
|
|
1068 |
@errors.generic.all |
|
1069 |
@errors.cyclades.connection |
|
1070 |
@errors.cyclades.server_id |
|
1071 |
@errors.cyclades.nic_id |
|
1072 |
def _run(self, nic_id, server_id): |
|
1073 |
num_of_disconnected = self.client.disconnect_server(server_id, nic_id) |
|
1074 |
if not num_of_disconnected: |
|
1075 |
raise ClientError( |
|
1076 |
'Network Interface %s not found on server %s' % ( |
|
1077 |
nic_id, server_id), |
|
1078 |
status=404) |
|
1079 |
print('Disconnected %s connections' % num_of_disconnected) |
|
1080 |
|
|
1081 |
def main(self, nic_id): |
|
1082 |
super(self.__class__, self)._run() |
|
1083 |
server_id = self._server_id_from_nic(nic_id=nic_id) |
|
1084 |
self._run(nic_id=nic_id, server_id=server_id) |
|
1085 |
|
|
1086 |
|
|
1087 |
@command(network_cmds) |
|
1088 | 868 |
class network_wait(_init_cyclades, _network_wait): |
1089 | 869 |
"""Wait for server to finish [PENDING, ACTIVE, DELETED]""" |
1090 | 870 |
|
... | ... | |
1194 | 974 |
|
1195 | 975 |
@command(ip_cmds) |
1196 | 976 |
class ip_attach(_init_cyclades, _optional_output_cmd): |
1197 |
"""Attach a floating IP to a server |
|
1198 |
""" |
|
1199 |
|
|
1200 |
@errors.generic.all |
|
1201 |
@errors.cyclades.connection |
|
1202 |
@errors.cyclades.server_id |
|
1203 |
def _run(self, server_id, ip): |
|
1204 |
self._optional_output(self.client.attach_floating_ip(server_id, ip)) |
|
977 |
"""DEPRECATED, use /port create""" |
|
1205 | 978 |
|
1206 |
def main(self, server_id, IP): |
|
1207 |
super(self.__class__, self)._run() |
|
1208 |
self._run(server_id=server_id, ip=IP) |
|
979 |
def main(self): |
|
980 |
raise CLISyntaxError('DEPRECATED, replaced by kamaki port create') |
|
1209 | 981 |
|
1210 | 982 |
|
1211 | 983 |
@command(ip_cmds) |
1212 | 984 |
class ip_detach(_init_cyclades, _optional_output_cmd): |
1213 |
"""Detach a floating IP from a server |
|
1214 |
""" |
|
1215 |
|
|
1216 |
@errors.generic.all |
|
1217 |
@errors.cyclades.connection |
|
1218 |
@errors.cyclades.server_id |
|
1219 |
def _run(self, server_id, ip): |
|
1220 |
self._optional_output(self.client.detach_floating_ip(server_id, ip)) |
|
985 |
"""DEPRECATED, use /port delete""" |
|
1221 | 986 |
|
1222 |
def main(self, server_id, IP): |
|
1223 |
super(self.__class__, self)._run() |
|
1224 |
self._run(server_id=server_id, ip=IP) |
|
987 |
def main(self): |
|
988 |
raise CLISyntaxError('DEPRECATED, replaced by kamaki port delete') |
Also available in: Unified diff