When specifying a new network interface in AWS you cannot specify
securitygroup:
- mysecuritygroup
network_interfaces:
- DeviceIndex: 0
PrivateIpAddresses:
- Primary: True
#auto assign public ip (not EIP)
AssociatePublicIpAddress: True
SubnetId: subnet-xxxx
Error code:
[ERROR ] AWS Response Status Code and Error: [400 400 Client Error: Bad Request] {'Errors': {'Error': {'Message': 'Network interfaces and an instance-level security groups may not be specified on the same request', 'Code': 'InvalidParameterCombination'}}, 'RequestID': '8f35e3fd-9dfe-49d9-8efd-b4944c2ba9ff'}
Might be good to clarify documentation for AWS network interfaces or create a code fix for this to allow specification of groups and interfaces on separate calls
@Enquier, thanks for the report. What is the output of salt --versions-report?
Salt: 2015.5.2
Python: 2.7.5 (default, Jun 24 2015, 00:41:19)
Jinja2: 2.7.2
M2Crypto: 0.21.1
msgpack-python: 0.4.6
msgpack-pure: Not Installed
pycrypto: 2.6.1
libnacl: Not Installed
PyYAML: 3.10
ioflo: Not Installed
PyZMQ: 14.3.1
RAET: Not Installed
ZMQ: 3.2.5
Mako: Not Installed
So the workaround that I discovered is to specify the security group by its id within the network interface:
network_interfaces:
- DeviceIndex: 0
PrivateIpAddresses:
- Primary: True
#auto assign public ip (not EIP)
AssociatePublicIpAddress: True
SubnetId: subnet-xxxx
SecurityGroupId:
- sg-xxxxxx
However this limits my use-case where I'd like to specify network connections (specifically subnets) and then extend to change the security groups for various machine types
@Enquier, thanks for the extra info.
Looking at the following, you are specifying a network device ID (presumably because of the "AssociatePublicIp") thus cannot specify SecurityGroupIds (VPC) when specifying NetworkInterfaces. You have to put the SecurityGroupIds on the network interfaces. SecurityGroups is only for Ec2, not VPC(Need to verify this).
One of the ways I see around this is to automatically associate public IP's on the specified subnet. This would require you specify 'subnetid' without the use of network interfaces.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-securitygroupids
def _create_eni_if_necessary(interface):
'''
Create an Elastic Interface if necessary and return a Network Interface Specification
'''
if 'NetworkInterfaceId' in interface and interface['NetworkInterfaceId'] is not None:
return {'DeviceIndex': interface['DeviceIndex'],
'NetworkInterfaceId': interface['NetworkInterfaceId']}
params = {'Action': 'DescribeSubnets'}
subnet_query = aws.query(params,
return_root=True,
location=get_location(),
provider=get_provider(),
opts=__opts__,
sigver='4')
found = False
for subnet_query_result in subnet_query:
if 'item' in subnet_query_result:
if isinstance(subnet_query_result['item'], dict):
for key, value in subnet_query_result['item'].iteritems():
if key == "subnetId":
if value == interface['SubnetId']:
found = True
break
else:
for subnet in subnet_query_result['item']:
if subnet['subnetId'] == interface['SubnetId']:
found = True
break
if not found:
raise SaltCloudConfigError(
'No such subnet <{0}>'.format(interface['SubnetId'])
)
params = {'SubnetId': interface['SubnetId']}
for k in ('Description', 'PrivateIpAddress',
'SecondaryPrivateIpAddressCount'):
if k in interface:
params[k] = interface[k]
for k in ('PrivateIpAddresses', 'SecurityGroupId'):
if k in interface:
params.update(_param_from_config(k, interface[k]))
params['Action'] = 'CreateNetworkInterface'
result = aws.query(params,
return_root=True,
location=get_location(),
provider=get_provider(),
opts=__opts__,
sigver='4')
eni_desc = result[1]
if not eni_desc or not eni_desc.get('networkInterfaceId'):
raise SaltCloudException('Failed to create interface: {0}'.format(result))
eni_id = eni_desc.get('networkInterfaceId')
log.debug(
'Created network interface {0} inst {1}'.format(
eni_id, interface['DeviceIndex']
)
)
associate_public_ip = interface.get('AssociatePublicIpAddress', False)
if isinstance(associate_public_ip, str):
# Assume id of EIP as value
_associate_eip_with_interface(eni_id, associate_public_ip)
elif interface.get('associate_eip'):
_associate_eip_with_interface(eni_id, interface.get('associate_eip'))
elif interface.get('allocate_new_eip') or associate_public_ip:
_new_eip = _request_eip(interface)
_associate_eip_with_interface(eni_id, _new_eip)
elif interface.get('allocate_new_eips'):
addr_list = _list_interface_private_addresses(eni_desc)
eip_list = []
for idx, addr in enumerate(addr_list):
eip_list.append(_request_eip(interface))
for idx, addr in enumerate(addr_list):
_associate_eip_with_interface(eni_id, eip_list[idx], addr)
Actually I primarily am specifying a network_interface for the subnetID. Certain subnets within my VPC are connected to my local network and route traffic differently. I would prefer to specify the subnet without the network interface but reading the documentation I was unable to determine how to do so.
http://docs.saltstack.com/en/latest/topics/cloud/aws.html#simple-launching-into-a-vpc
Reading that, you should be able to specify 'subnetid' without the use of network interfaces.
Guess I didn't read the documentation as thoroughly as I thought! I'll give it a whirl and report back
If you're no longer running into issues, I think this can be closed.
I was able to confirm @AkhterAli 's solution works. This issue can be closed
Worked for me also thanks for the help everyone.
Most helpful comment
So the workaround that I discovered is to specify the security group by its id within the network interface:
However this limits my use-case where I'd like to specify network connections (specifically subnets) and then extend to change the security groups for various machine types