Skip to content

Commit e6f843d

Browse files
committed
Merge pull request saltstack#18650 from bbeausej/develop
salt-cloud GCE : Support for addresses & internal IPs
2 parents d89a204 + b906aa9 commit e6f843d

File tree

2 files changed

+273
-11
lines changed

2 files changed

+273
-11
lines changed

doc/topics/cloud/gce.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,19 @@ typically also include a hard-coded default.
208208
#
209209
delete_boot_pd: False
210210
211+
# Specify whether to use public or private IP for deploy script.
212+
# Valid options are:
213+
# private_ips - The salt-master is also hosted with GCE
214+
# public_ips - The salt-master is hosted outside of GCE
215+
ssh_interface: public_ips
216+
217+
# Per instance setting: Used a named fixed IP address to this host.
218+
# Valid options are:
219+
# ephemeral - The host will use a GCE ephemeral IP
220+
# None - No external IP will be configured on this host.
221+
# Optionally, pass the name of a GCE address to use a fixed IP address.
222+
# If the address does not already exist, it will be created.
223+
external_ip: "ephemeral"
211224
212225
GCE instances do not allow remote access to the root user by default.
213226
Instead, another user must be used to run the deploy script using sudo.
@@ -403,6 +416,30 @@ Specify the network name to view information about the network.
403416
404417
salt-cloud -f show_network gce name=mynet
405418
419+
Create address
420+
---------------
421+
Create a new named static IP address in a region.
422+
423+
.. code-block:: bash
424+
425+
salt-cloud -f create_address gce name=my-fixed-ip region=us-central1
426+
427+
Delete address
428+
---------------
429+
Delete an existing named fixed IP address.
430+
431+
.. code-block:: bash
432+
433+
salt-cloud -f delete_address gce name=my-fixed-ip region=us-central1
434+
435+
Show address
436+
---------------
437+
View details on a named address.
438+
439+
.. code-block:: bash
440+
441+
salt-cloud -f show_address gce name=my-fixed-ip region=us-central1
442+
406443
Create firewall
407444
---------------
408445
You'll need to create custom firewall rules if you want to allow other traffic
@@ -477,6 +514,12 @@ requires the name.
477514
salt-cloud -f delete_lb gce name=lb
478515
salt-cloud -f show_lb gce name=lb
479516
517+
You can also create a load balancer using a named fixed IP addressby specifying the name of the address.
518+
If the address does not exist yet it will be created.
519+
520+
.. code-block:: bash
521+
522+
salt-cloud -f create_lb gce name=my-lb region=us-central1 ports=234 members=s1,s2,s3 address=my-lb-ip
480523
481524
Attach and Detach LB
482525
--------------------

salt/cloud/clouds/gce.py

Lines changed: 230 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
# The location of the private key (PEM format)
5353
service_account_private_key: /home/erjohnso/PRIVKEY.pem
5454
provider: gce
55+
# Specify whether to use public or private IP for deploy script.
56+
# Valid options are:
57+
# private_ips - The salt-master is also hosted with GCE
58+
# public_ips - The salt-master is hosted outside of GCE
59+
ssh_interface: public_ips
5560
5661
:maintainer: Eric Johnson <erjohnso@google.com>
5762
:maturity: new
@@ -229,6 +234,16 @@ def _expand_disk(disk):
229234
return ret
230235

231236

237+
def _expand_address(addy):
238+
'''
239+
Convert the libcloud GCEAddress object into something more serializable.
240+
'''
241+
ret = {}
242+
ret.update(addy.__dict__)
243+
ret['extra']['zone'] = addy.region.name
244+
return ret
245+
246+
232247
def _expand_balancer(lb):
233248
'''
234249
Convert the libcloud load-balancer object into something more serializable.
@@ -404,14 +419,25 @@ def __get_metadata(vm_):
404419
return metadata
405420

406421

407-
def __get_host(node):
422+
def __get_host(node, vm_):
408423
'''
409424
Return public IP, private IP, or hostname for the libcloud 'node' object
410425
'''
411-
if len(node.public_ips) > 0:
412-
return node.public_ips[0]
413-
if len(node.private_ips) > 0:
414-
return node.private_ips[0]
426+
if __get_ssh_interface(vm_) == 'private_ips':
427+
ip_address = node.private_ips[0]
428+
log.info('Salt node data. Private_ip: {0}'.format(ip_address))
429+
else:
430+
ip_address = node.public_ips[0]
431+
log.info('Salt node data. Public_ip: {0}'.format(ip_address))
432+
433+
# if len(node.public_ips) > 0:
434+
# return node.public_ips[0]
435+
# if len(node.private_ips) > 0:
436+
# return node.private_ips[0]
437+
438+
if len(ip_address) > 0:
439+
return ip_address
440+
415441
return node.name
416442

417443

@@ -425,6 +451,35 @@ def __get_network(conn, vm_):
425451
return conn.ex_get_network(network)
426452

427453

454+
def __get_ssh_interface(vm_):
455+
'''
456+
Return the ssh_interface type to connect to. Either 'public_ips' (default)
457+
or 'private_ips'.
458+
'''
459+
return config.get_cloud_config_value(
460+
'ssh_interface', vm_, __opts__, default='public_ips',
461+
search_global=False
462+
)
463+
464+
465+
def __create_orget_address(conn, name, region):
466+
'''
467+
Reuse or create a static IP address.
468+
Returns a native GCEAddress construct to use with libcloud.
469+
'''
470+
try:
471+
addy = conn.ex_get_address(name, region)
472+
except ResourceNotFoundError: # pylint: disable=W0703
473+
addr_kwargs = {
474+
'name': name,
475+
'region': region
476+
}
477+
new_addy = create_address(addr_kwargs, "function")
478+
addy = conn.ex_get_address(new_addy['name'], new_addy['region'])
479+
480+
return addy
481+
482+
428483
def _parse_allow(allow):
429484
'''
430485
Convert firewall rule allowed user-string to specified REST API format.
@@ -928,6 +983,161 @@ def show_hc(kwargs=None, call=None):
928983
return _expand_item(conn.ex_get_healthcheck(kwargs['name']))
929984

930985

986+
def create_address(kwargs=None, call=None):
987+
'''
988+
Create a static address in a region.
989+
990+
CLI Example:
991+
992+
.. code-block:: bash
993+
994+
salt-cloud -f create_address gce name=my-ip region=us-central1 address=IP
995+
'''
996+
if call != 'function':
997+
raise SaltCloudSystemExit(
998+
'The create_address function must be called with -f or --function.'
999+
)
1000+
1001+
if not kwargs or 'name' not in kwargs:
1002+
log.error(
1003+
'A name must be specified when creating an address.'
1004+
)
1005+
return False
1006+
if 'region' not in kwargs:
1007+
log.error(
1008+
'A region must be specified for the address.'
1009+
)
1010+
return False
1011+
1012+
name = kwargs['name']
1013+
ex_region = kwargs['region']
1014+
ex_address = kwargs.get("address", None)
1015+
1016+
conn = get_conn()
1017+
1018+
salt.utils.cloud.fire_event(
1019+
'event',
1020+
'create address',
1021+
'salt/cloud/address/creating',
1022+
kwargs,
1023+
transport=__opts__['transport']
1024+
)
1025+
1026+
addy = conn.ex_create_address(name, ex_region, ex_address)
1027+
1028+
salt.utils.cloud.fire_event(
1029+
'event',
1030+
'created address',
1031+
'salt/cloud/address/created',
1032+
kwargs,
1033+
transport=__opts__['transport']
1034+
)
1035+
1036+
log.info('Created GCE Address '+name)
1037+
1038+
return _expand_address(addy)
1039+
1040+
1041+
def delete_address(kwargs=None, call=None):
1042+
'''
1043+
Permanently delete a static address.
1044+
1045+
CLI Example:
1046+
1047+
.. code-block:: bash
1048+
1049+
salt-cloud -f delete_address gce name=my-ip
1050+
'''
1051+
if call != 'function':
1052+
raise SaltCloudSystemExit(
1053+
'The delete_address function must be called with -f or --function.'
1054+
)
1055+
1056+
if not kwargs or 'name' not in kwargs:
1057+
log.error(
1058+
'A name must be specified when deleting an address.'
1059+
)
1060+
return False
1061+
1062+
if not kwargs or 'region' not in kwargs:
1063+
log.error(
1064+
'A region must be specified when deleting an address.'
1065+
)
1066+
return False
1067+
1068+
name = kwargs['name']
1069+
ex_region = kwargs['region']
1070+
1071+
conn = get_conn()
1072+
1073+
salt.utils.cloud.fire_event(
1074+
'event',
1075+
'delete address',
1076+
'salt/cloud/address/deleting',
1077+
{
1078+
'name': name,
1079+
},
1080+
transport=__opts__['transport']
1081+
)
1082+
1083+
try:
1084+
result = conn.ex_destroy_address(
1085+
conn.ex_get_address(name, ex_region)
1086+
)
1087+
except ResourceNotFoundError as exc:
1088+
log.error(
1089+
'Address {0} could not be found (region {1})\n'
1090+
'The following exception was thrown by libcloud:\n{2}'.format(
1091+
name, ex_region, exc),
1092+
exc_info_on_loglevel=logging.DEBUG
1093+
)
1094+
return False
1095+
1096+
salt.utils.cloud.fire_event(
1097+
'event',
1098+
'deleted address',
1099+
'salt/cloud/address/deleted',
1100+
{
1101+
'name': name,
1102+
},
1103+
transport=__opts__['transport']
1104+
)
1105+
1106+
log.info('Deleted GCE Address ' + name)
1107+
1108+
return result
1109+
1110+
1111+
def show_address(kwargs=None, call=None):
1112+
'''
1113+
Show the details of an existing static address.
1114+
1115+
CLI Example:
1116+
1117+
.. code-block:: bash
1118+
1119+
salt-cloud -f show_address gce name=mysnapshot region=us-central1
1120+
'''
1121+
if call != 'function':
1122+
raise SaltCloudSystemExit(
1123+
'The show_snapshot function must be called with -f or --function.'
1124+
)
1125+
if not kwargs or 'name' not in kwargs:
1126+
log.error(
1127+
'Must specify name.'
1128+
)
1129+
return False
1130+
1131+
if not kwargs or 'region' not in kwargs:
1132+
log.error(
1133+
'Must specify region.'
1134+
)
1135+
return False
1136+
1137+
conn = get_conn()
1138+
return _expand_address(conn.ex_get_address(kwargs['name'], kwargs['region']))
1139+
1140+
9311141
def create_lb(kwargs=None, call=None):
9321142
'''
9331143
Create a load-balancer configuration.
@@ -972,15 +1182,19 @@ def create_lb(kwargs=None, call=None):
9721182
protocol = kwargs.get('protocol', 'tcp')
9731183
algorithm = kwargs.get('algorithm', None)
9741184
ex_healthchecks = kwargs.get('healthchecks', None)
1185+
9751186
# pylint: disable=W0511
976-
# TODO(erjohnso): need to support GCEAddress, but that requires adding
977-
# salt functions to create/destroy/show address...
978-
ex_address = None
1187+
1188+
conn = get_conn()
1189+
lb_conn = get_lb_conn(conn)
1190+
1191+
ex_address = kwargs.get('address', None)
1192+
if ex_address is not None:
1193+
ex_address = __create_orget_address(conn, ex_address, ex_region)
1194+
9791195
if ex_healthchecks:
9801196
ex_healthchecks = ex_healthchecks.split(',')
9811197

982-
lb_conn = get_lb_conn(get_conn())
983-
9841198
salt.utils.cloud.fire_event(
9851199
'event',
9861200
'create load_balancer',
@@ -1327,6 +1541,7 @@ def delete_disk(kwargs=None, call=None):
13271541

13281542

13291543
def create_disk(kwargs=None, call=None):
1544+
13301545
'''
13311546
Create a new persistent disk. Must specify `disk_name` and `location`.
13321547
Can also specify an `image` or `snapshot` but if neither of those are
@@ -1821,6 +2036,7 @@ def create(vm_=None, call=None):
18212036
}
18222037

18232038
if LIBCLOUD_VERSION_INFO > (0, 15, 1):
2039+
18242040
# This only exists in current trunk of libcloud and should be in next
18252041
# release
18262042
kwargs.update({
@@ -1837,6 +2053,9 @@ def create(vm_=None, call=None):
18372053

18382054
if 'external_ip' in kwargs and kwargs['external_ip'] == "None":
18392055
kwargs['external_ip'] = None
2056+
elif kwargs['external_ip'] != 'ephemeral':
2057+
region = '-'.join(kwargs['location'].name.split('-')[:2])
2058+
kwargs['external_ip'] = __create_orget_address(conn, kwargs['external_ip'], region)
18402059

18412060
log.info('Creating GCE instance {0} in {1}'.format(vm_['name'],
18422061
kwargs['location'].name)
@@ -1879,7 +2098,7 @@ def create(vm_=None, call=None):
18792098
ssh_user, ssh_key = __get_ssh_credentials(vm_)
18802099
deploy_kwargs = {
18812100
'opts': __opts__,
1882-
'host': __get_host(node_data),
2101+
'host': __get_host(node_data, vm_),
18832102
'username': ssh_user,
18842103
'key_filename': ssh_key,
18852104
'script': deploy_script.script,

0 commit comments

Comments
 (0)