Possibility to launch instances with public IPs
selshowk opened this issue · 7 comments
Assigning a public IP directly to an instance is simpler than using a floating IP (e.g. elastic IPs in AWS have stringent limits).
On AWS it seems like we can launch an instance with a public IP simply by setting a flag in thenetwork section of "create_instances" boto call. I'm not sure if GCP or Azure have similar flags but it would be useful to be able to pass in this flag either directly in the InstanceService.create() function or via a kwarg that's passed through by the AWS implementation (and maybe the others). This is done for e.g. the iam_instance_profile now. Is there a reason not to do this or would there be a better way to do it?
@afgane @almahmoud Any thoughts on this issue?
Here is a working minimal modification for the instance create
function in AWS provider. In this case implementation I use a flag to determine whether to use a public IP but it could, in principle, be in the kwargs:
def create(self, label, image, vm_type, subnet,
key_pair=None, vm_firewalls=None, user_data=None,
launch_config=None,
associate_public_ip = False,
**kwargs):
AWSInstance.assert_valid_resource_label(label)
image_id = image.id if isinstance(image, MachineImage) else image
vm_size = vm_type.id if \
isinstance(vm_type, VMType) else vm_type
subnet = (self.provider.networking.subnets.get(subnet)
if isinstance(subnet, str) else subnet)
zone_name = self.provider.zone_name
key_pair_name = key_pair.name if isinstance(
key_pair,
KeyPair) else key_pair
if launch_config:
bdm = self._process_block_device_mappings(launch_config)
else:
bdm = None
subnet_id, zone_id, vm_firewall_ids = \
self._resolve_launch_options(subnet, zone_name, vm_firewalls)
placement = {'AvailabilityZone': zone_id} if zone_id else None
network_interfaces = [{
'DeviceIndex': 0,
'SubnetId' : f"{subnet_id}",
'Groups': vm_firewall_ids,
'AssociatePublicIpAddress': True,
'DeleteOnTermination': True,
}] if associate_public_ip else None
# if using a network interface we don't set subnet or groups
if network_interfaces:
vm_firewall_ids = None
subnet_id = None
inst = self.svc.create(
'create_instances',
ImageId=image_id,
MinCount=1,
MaxCount=1,
KeyName=key_pair_name,
SecurityGroupIds=vm_firewall_ids or None,
UserData=str(user_data) or None,
InstanceType=vm_size,
Placement=placement,
BlockDeviceMappings=bdm,
SubnetId=subnet_id,
IamInstanceProfile=kwargs.pop('iam_instance_profile', None),
NetworkInterfaces=network_interfaces
)
if inst and len(inst) == 1:
# Wait until the resource exists
# pylint:disable=protected-access
inst[0]._wait_till_exists()
# Tag the instance w/ the name
inst[0].label = label
return inst[0]
raise ValueError(
'Expected a single object response, got a list: %s' % inst)
I've skimmed the azure implementation and I think a similar thing can be accomplished by setting a public ip in the nic_params
as done e.g. here. Though from that link it seems the address might have to be created manually for azure.
@selshowk I'm not sure we'll be able to introduce a top level parameter, since it probably won't be possible to make this work in a cloud-independent way. In the MS sample you sent for example, there's logic for manually creating a public ip. OpenStack's public ip assignment is network dependent, and the standard way is to use a floating ip.
We'd be happy to accept to a PR through kwargs for AWS though. (in the same way that iam_instance_profile
is handled)
Ok, I am currently implementing a multi-cloud solution using cloudbridge and will try to provide PRs for the above functionality as I figure out how/if its possible for each provider.
I haven't generated a PR yet and the functionality is not yet there so not sure. Feel free to keep/close it as you like.