|
1 | 1 | from __future__ import absolute_import, division, print_function
|
2 | 2 |
|
| 3 | +import botocore |
3 | 4 | import configparser
|
4 | 5 | import ipaddress
|
5 | 6 | import logging
|
@@ -225,6 +226,70 @@ def validated_name(role_name, fallback_suffix):
|
225 | 226 | spot_fleet_role_name = validated_name(spot_fleet_role_name,
|
226 | 227 | 'spot-fleet-role')
|
227 | 228 |
|
| 229 | + # Check the user supplied policies. Remove redundant entries |
| 230 | + if isinstance(policies, six.string_types): |
| 231 | + input_policies = {policies} |
| 232 | + else: |
| 233 | + try: |
| 234 | + if all(isinstance(x, six.string_types) for x in policies): |
| 235 | + input_policies = set(list(policies)) |
| 236 | + else: |
| 237 | + raise aws.CloudknotInputError( |
| 238 | + 'policies must be a string or a ' |
| 239 | + 'sequence of strings.' |
| 240 | + ) |
| 241 | + except TypeError: |
| 242 | + raise aws.CloudknotInputError('policies must be a string ' |
| 243 | + 'or a sequence of strings') |
| 244 | + |
| 245 | + # Validate policies against the available policies |
| 246 | + policy_arns = [] |
| 247 | + policy_names = [] |
| 248 | + for policy in input_policies: |
| 249 | + try: |
| 250 | + aws.clients['iam'].get_policy(PolicyArn=policy) |
| 251 | + policy_arns.append(policy) |
| 252 | + except ( |
| 253 | + aws.clients['iam'].exceptions.InvalidInputException, |
| 254 | + aws.clients['iam'].exceptions.NoSuchEntityException, |
| 255 | + botocore.exceptions.ParamValidationError, |
| 256 | + ): |
| 257 | + policy_names.append(policy) |
| 258 | + |
| 259 | + if policy_names: |
| 260 | + # Get all AWS policies |
| 261 | + response = aws.clients['iam'].list_policies() |
| 262 | + aws_policies = {d['PolicyName']: d['Arn'] |
| 263 | + for d in response.get('Policies')} |
| 264 | + |
| 265 | + # If results are paginated, continue appending to aws_policies, |
| 266 | + # using `Marker` to tell next call where to start |
| 267 | + while response['IsTruncated']: |
| 268 | + response = aws.clients['iam'].list_policies( |
| 269 | + Marker=response['Marker'] |
| 270 | + ) |
| 271 | + aws_policies.update( |
| 272 | + {d['PolicyName']: d['Arn'] |
| 273 | + for d in response.get('Policies')} |
| 274 | + ) |
| 275 | + |
| 276 | + # If input policies are not subset of aws_policies, throw error |
| 277 | + if not (set(policy_names) < set(aws_policies.keys())): |
| 278 | + bad_policies = set(policy_names) - set(aws_policies.keys()) |
| 279 | + raise aws.CloudknotInputError( |
| 280 | + 'Could not find the policies {bad_policies!s} on ' |
| 281 | + 'AWS.'.format(bad_policies=bad_policies) |
| 282 | + ) |
| 283 | + |
| 284 | + policy_arns += [aws_policies[policy] |
| 285 | + for policy in policy_names] |
| 286 | + |
| 287 | + s3_params = aws.get_s3_params() |
| 288 | + policy_list = [s3_params.policy_arn] + [ |
| 289 | + policy for policy in policy_arns |
| 290 | + ] |
| 291 | + policies = ','.join(policy_list) |
| 292 | + |
228 | 293 | if use_default_vpc:
|
229 | 294 | if any([ipv4_cidr, instance_tenancy]):
|
230 | 295 | raise aws.CloudknotInputError(
|
@@ -276,12 +341,6 @@ def validated_name(role_name, fallback_suffix):
|
276 | 341 | with open(template_path, 'r') as fp:
|
277 | 342 | template_body = fp.read()
|
278 | 343 |
|
279 |
| - s3_params = aws.get_s3_params() |
280 |
| - policy_list = [s3_params.policy_arn] + [ |
281 |
| - policy for policy in policies |
282 |
| - ] |
283 |
| - policies = ','.join(policy_list) |
284 |
| - |
285 | 344 | response = aws.clients['cloudformation'].create_stack(
|
286 | 345 | StackName=self.name + '-pars',
|
287 | 346 | TemplateBody=template_body,
|
@@ -403,12 +462,6 @@ def validated_name(role_name, fallback_suffix):
|
403 | 462 | with open(template_path, 'r') as fp:
|
404 | 463 | template_body = fp.read()
|
405 | 464 |
|
406 |
| - s3_params = aws.get_s3_params() |
407 |
| - policy_list = [s3_params.policy_arn] + [ |
408 |
| - policy for policy in policies |
409 |
| - ] |
410 |
| - policies = ','.join(policy_list) |
411 |
| - |
412 | 465 | response = aws.clients['cloudformation'].create_stack(
|
413 | 466 | StackName=self.name + '-pars',
|
414 | 467 | TemplateBody=template_body,
|
|
0 commit comments