Code Monkey home page Code Monkey logo

troposphere's Introduction

troposphere

PyPI Version Build Status license: New BSD license Documentation Status

About

troposphere - library to create AWS CloudFormation descriptions

The troposphere library allows for easier creation of the AWS CloudFormation JSON by writing Python code to describe the AWS resources. troposphere also includes some basic support for OpenStack resources via Heat.

To facilitate catching CloudFormation or JSON errors early the library has property and type checking built into the classes.

Installation

troposphere can be installed using the pip distribution system for Python by issuing:

$ pip install troposphere

To install troposphere with awacs (recommended soft dependency):

$ pip install troposphere[policy]

Alternatively, you can use setup.py to install by cloning this repository and issuing:

$ python setup.py install  # you may need sudo depending on your python installation

Examples

A simple example to create an instance would look like this:

>>> from troposphere import Ref, Template
>>> import troposphere.ec2 as ec2
>>> t = Template()
>>> instance = ec2.Instance("myinstance")
>>> instance.ImageId = "ami-951945d0"
>>> instance.InstanceType = "t1.micro"
>>> t.add_resource(instance)
<troposphere.ec2.Instance object at 0x101bf3390>
>>> print(t.to_json())
{
    "Resources": {
        "myinstance": {
            "Properties": {
                "ImageId": "ami-951945d0",
                "InstanceType": "t1.micro"
            },
            "Type": "AWS::EC2::Instance"
        }
    }
}
>>> print(t.to_yaml())
Resources:
    myinstance:
        Properties:
            ImageId: ami-951945d0
            InstanceType: t1.micro
        Type: AWS::EC2::Instance

Alternatively, parameters can be used instead of properties:

>>> instance = ec2.Instance("myinstance", ImageId="ami-951945d0", InstanceType="t1.micro")
>>> t.add_resource(instance)
<troposphere.ec2.Instance object at 0x101bf3550>

And add_resource() returns the object to make it easy to use with Ref():

>>> instance = t.add_resource(ec2.Instance("myinstance", ImageId="ami-951945d0", InstanceType="t1.micro"))
>>> Ref(instance)
<troposphere.Ref object at 0x101bf3490>

Examples of the error checking (full tracebacks removed for clarity):

Incorrect property being set on AWS resource:

>>> import troposphere.ec2 as ec2
>>> ec2.Instance("ec2instance", image="i-XXXX")
Traceback (most recent call last):
...
AttributeError: AWS::EC2::Instance object does not support attribute image

Incorrect type for AWS resource property:

>>> ec2.Instance("ec2instance", ImageId=1)
Traceback (most recent call last):
...
TypeError: ImageId is <type 'int'>, expected <type 'basestring'>

Missing required property for the AWS resource:

>>> from troposphere import Template
>>> import troposphere.ec2 as ec2
>>> t = Template()
>>> t.add_resource(ec2.Subnet("ec2subnet", VpcId="vpcid"))
<troposphere.ec2.Subnet object at 0x100830ed0>
>>> print(t.to_json())
Traceback (most recent call last):
...
ValueError: Resource CidrBlock required in type AWS::EC2::Subnet (title: ec2subnet)

Currently supported resource types

Duplicating a single instance sample would look like this

# Converted from EC2InstanceSample.template located at:
# http://aws.amazon.com/cloudformation/aws-cloudformation-templates/

from troposphere import Base64, FindInMap, GetAtt
from troposphere import Parameter, Output, Ref, Template
import troposphere.ec2 as ec2


template = Template()

keyname_param = template.add_parameter(Parameter(
    "KeyName",
    Description="Name of an existing EC2 KeyPair to enable SSH "
                "access to the instance",
    Type="String",
))

template.add_mapping('RegionMap', {
    "us-east-1":      {"AMI": "ami-7f418316"},
    "us-west-1":      {"AMI": "ami-951945d0"},
    "us-west-2":      {"AMI": "ami-16fd7026"},
    "eu-west-1":      {"AMI": "ami-24506250"},
    "sa-east-1":      {"AMI": "ami-3e3be423"},
    "ap-southeast-1": {"AMI": "ami-74dda626"},
    "ap-northeast-1": {"AMI": "ami-dcfa4edd"}
})

ec2_instance = template.add_resource(ec2.Instance(
    "Ec2Instance",
    ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"),
    InstanceType="t1.micro",
    KeyName=Ref(keyname_param),
    SecurityGroups=["default"],
    UserData=Base64("80")
))

template.add_output([
    Output(
        "InstanceId",
        Description="InstanceId of the newly created EC2 instance",
        Value=Ref(ec2_instance),
    ),
    Output(
        "AZ",
        Description="Availability Zone of the newly created EC2 instance",
        Value=GetAtt(ec2_instance, "AvailabilityZone"),
    ),
    Output(
        "PublicIP",
        Description="Public IP address of the newly created EC2 instance",
        Value=GetAtt(ec2_instance, "PublicIp"),
    ),
    Output(
        "PrivateIP",
        Description="Private IP address of the newly created EC2 instance",
        Value=GetAtt(ec2_instance, "PrivateIp"),
    ),
    Output(
        "PublicDNS",
        Description="Public DNSName of the newly created EC2 instance",
        Value=GetAtt(ec2_instance, "PublicDnsName"),
    ),
    Output(
        "PrivateDNS",
        Description="Private DNSName of the newly created EC2 instance",
        Value=GetAtt(ec2_instance, "PrivateDnsName"),
    ),
])

print(template.to_json())

Community

We have a Google Group, cloudtools-dev, where you can ask questions and engage with the troposphere community. Issues and pull requests are always welcome!

Licensing

troposphere is licensed under the BSD 2-Clause license. See LICENSE for the troposphere full license text.

troposphere's People

Contributors

andybotting avatar axelpavageau avatar axelpavageauekino avatar benbridts avatar bobveznat avatar chrisgilmerproj avatar echernyavskiy avatar edubxb avatar fungusakafungus avatar github-actions[bot] avatar gkrizek avatar gsoyka avatar hltbra avatar iblazevic avatar itprokyle avatar jcoleman avatar jeanphix avatar jerry153fish avatar johnpreston avatar jonapich avatar markpeek avatar mbrossard avatar michael-k avatar mwildehahn avatar oussemos avatar patmyron avatar philtay avatar phobologic avatar rcuza avatar stevengorrell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

troposphere's Issues

Question: template to troposphere source?

Hi, nice work! This is not an issue, just a question: is there a template to troposphere source tool (the inverse of troposphere)?

I notice that the troposphere examples are all converted from CloudFormation templates hosted by AWS at http://aws.amazon.com/cloudformation/aws-cloudformation-templates/. Did you guys write that source code manually, or do you have a tool that parses existing templates and produces (as far as possible) the equivalent troposphere source code? That might also be a useful tool (and even better might be a Python script that could be launched on an instance within a VPC that describes the entire VPC and spits out troposphere source, like AWS CloudFormer already does but with the extra step to produce troposphere source). Thanks for all the hard work.

Autoscaling MinSize from a Reference

I haven't got the time tonight to investigate a fix and I'm still a bit new with troposphere but really liking it :)

I've got many scores of resources created (SGs, Roles, NAT instances, Subnets, Routes) and successfully launched CF templates and had the expected results - wow!

I'm trying to do an autoscaling group. I note that "MinSize" is a "positive_integer"

I keep getting ValueError() when I try to generate AutoScalingGroup and the failure is down to MinSize resolution

I really need that to be a parameter. Reason is, that sometimes I use the template for production stack at full capacity (say min servers = 6) and sometimes dev stack (say min_servers = 1)

I wanted to get this down as a ticket before I left tonight and see if you had any ideas or experience of this and could suggest a workaround or fix. I tried modding the code for positive_integer() to look a bit like integer() but it couldn't really get it working for me

I've tried hardcoding the resource name and a ref (which I prefer) - neither works.

Sorry that is not a lot to go on.

Fragments:

    self.xxx_min_servers_param = self.template.add_parameter(Parameter(
        "MinXXXServers",
        Description="The minimum number of xxx servers to be in service",
        Type="Number",
        MinValue="1",
        Default="1",
        MaxValue="9",
        ConstraintDescription="Minimum number of XXX servers must be a number"
    ))

...

    self.xxx_server_group = self.template.add_resource(autoscaling.AutoScalingGroup(
        "XxxServerGroup",
        AvailabilityZones=GetAZs(""),
        VPCZoneIdentifier=[ Ref(self.my_subnet_AZa), Ref(self.my_subnet_AZb), Ref(self.y_subnet_AZc) ],
        MinSize=Ref("MinXXXServers"),
        MaxSize=Ref(self.xxx_min_servers_param),
        LoadBalancerNames=[ Ref(self.xxx_elb) ],
        LaunchConfigurationName=Ref(self.xxx_launch_config),
    ))

Referencing a parameter displays String value

Using the code from the examples:

from troposphere import Ref, Template, Parameter, Join, GetAtt
import troposphere.ec2 as ec2
from troposphere.route53 import RecordSetType

t = Template()

keyname_param = t.add_parameter(Parameter(
    "KeyName",
    Description="Name of an existing EC2 KeyPair to enable SSH access to the instance",
    Type="String",
))

instance = ec2.Instance("myinstance", ImageId="ami-951945d0", InstanceType="t1.micro", KeyName=Ref(keyname_param))
t.add_resource(instance)

print(t.to_json())

Outputs:

python
Python 2.6.8 (unknown, Mar 14 2013, 09:31:22) 
[GCC 4.6.2 20111027 (Red Hat 4.6.2-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from troposphere import Ref, Template, Parameter, Join, GetAtt
>>> import troposphere.ec2 as ec2
>>> from troposphere.route53 import RecordSetType
>>> 
>>> t = Template()
>>> 
>>> keyname_param = t.add_parameter(Parameter(
...     "KeyName",
...     Description="Name of an existing EC2 KeyPair to enable SSH access to the instance",
...     Type="String",
... ))
>>> 
>>> instance = ec2.Instance("myinstance", ImageId="ami-951945d0", InstanceType="t1.micro", KeyName=Ref(keyname_param))
>>> t.add_resource(instance)
<troposphere.ec2.Instance object at 0x7fb4b883fed0>
>>> 
>>> print(t.to_json())
{
    "Parameters": {
        "KeyName": {
            "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instance", 
            "Type": "String"
        }
    }, 
    "Resources": {
        "myinstance": {
            "Properties": {
                "ImageId": "ami-951945d0", 
                "InstanceType": "t1.micro", 
                "KeyName": {
                    "Ref": {
                        "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instance", 
                        "Type": "String"
                    }
                }
            }, 
            "Type": "AWS::EC2::Instance"
        }
    }
}

The reference to the keyname displays description and type. I'm using version 0.3.2 and have tried it on various python versions. 2.7.1, 2.7.2 and 2.6.8.

            "KeyName": {
                "Ref": {
                    "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instance", 
                    "Type": "String"
                }
            }

Something obvious?

Thanks,

Support for Logs

Sorry for not creating a pull request, but please find below the code to support the new Logs resource type.

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-metricfilter.html

Put it in /troposphere/logs.py.

from . import AWSObject, AWSProperty
from .validators import positive_integer

class LogGroup(AWSObject):
    type = "AWS::Logs::LogGroup"

    props = {
        'RetentionInDays': (positive_integer, False),
    }

class MetricTransformation(AWSProperty):
    props = {
        'MetricName': (basestring, True),
        'MetricNamespace': (basestring, True),
        'MetricValue': (basestring, True),
    }

class MetricFilter(AWSObject):
    type = "AWS::Logs::MetricFilter"

    props = {
        'FilterPattern': ([basestring], True),
        'LogGroupName': (basestring, True),
        'MetricTransformations': ([MetricTransformation], True),
    }

cfn2py exception "expected string, NoneType found"

Hi,

I've been running cfn2py against a number of CF templates and have found that the cfn2py script generally fails with the same symptoms:

Traceback (most recent call last):
File "cfn2py", line 229, in
globals()"do_" + s.lower()
File "cfn2py", line 128, in do_resources
print ' %s=%s,' % (pk, output_value(pv))
File "cfn2py", line 178, in output_value
return "[" + ", ".join(out) + "]"
TypeError: sequence item 0: expected string, NoneType found

In terms of what's happening in the code, output_value(v) is being passed a dict as parameter v but it expects basestring, bool, or list so it fails to process the dict and falls through to the function_map test which does nothing, and finally output_value(v) implicitly returns None, causing the subsequent "expected string, NoneType found" error.

Same symptoms parsing numerous constructs, such as NetworkInterfaces within an AWS::EC2::Instance definition.

Thanks.

Elasticache VPC properties missing

In order to make elasticache instances work in troposphere I made the following changes:

    props = {
        'AutoMinorVersionUpgrade': (bool, False),
        'CacheNodeType': (basestring, True),
        'CacheParameterGroupName': (basestring, False),
        'CacheSecurityGroupNames': (list, False),
        'Engine': (basestring, True),
        'EngineVersion': (basestring, False),
        'NotificationTopicArn': (basestring, False),
        'NumCacheNodes': (integer, False),
        'Port': (int, False),
        'PreferredAvailabilityZone': (basestring, False),
        'PreferredMaintenanceWindow': (basestring, False),
        'VpcSecurityGroupIds': (list, False),
        'CacheSubnetGroupName': (basestring, False),
    }

Can you add VPC support for Elasticache?

Thanks,
Pierre

Is it possible to use if statements in the resource declaration?

I would like to do something like this

    t.add_resource(rds.DBInstance(
        rds_name,
        VPCSecurityGroups=[Ref(params['EnvironmentSecurityGroupId']), Ref(params['MonitoringSecurityGroup'])],
        DBSubnetGroupName=Ref(subnet_group),
        DBParameterGroupName=Ref(rds_parameter_group),
        AllocatedStorage=rds_instance["db"]["allocated_storage"],
        AutoMinorVersionUpgrade=rds_instance["db"]["auto_minor_version_upgrade"],
        DBInstanceClass=rds_instance["db"]["instance_class"],
        EngineVersion=rds_instance["db"]["engine_version"],
        Engine="MySQL",
        MultiAZ=rds_instance["db"]["multiaz"],
        MasterUsername=rds_instance["db"]["master_username"],
        MasterUserPassword=Ref(params['DbPasswd']),
        if "snapshot" in rds_instance["db"]:
             DBSnapshotIdentifier=rds_instance["db"]["snapshot"][env],
        Tags=tag_list
    ))

or

First create the rds template and then if there is a snapshot identifier I could add it to the resource.

Is this possible?

Thanks,
Pierre

AuditScalingGroup TerminationPolicies not implemented

I know this is mentioned in the README but I wanted to open an issue to track it.

I've locally hacked it in with the following code

class AutoScalingGroup(asc.AutoScalingGroup):
    props = {
        'AvailabilityZones': (list, True),
        'Cooldown': (asc.integer, False),
        'DesiredCapacity': (asc.integer, False),
        'HealthCheckGracePeriod': (int, False),
        'HealthCheckType': (basestring, False),
        'InstanceId': (basestring, False),
        'LaunchConfigurationName': (basestring, True),
        'LoadBalancerNames': (list, False),
        'MaxSize': (asc.positive_integer, True),
        'MinSize': (asc.positive_integer, True),
        'NotificationConfiguration': (asc.NotificationConfiguration, False),
        'Tags': (list, False),  # Although docs say these are required
        'VPCZoneIdentifier': (list, False),
        'TerminationPolicies': (list, False),
    }


class TerminationPolicies(object):
    Default = 'Default'
    OldestInstance = 'OldestInstance'
    NewestInstance = 'NewestInstance'
    OldestLaunchConfiguration = 'OldestLaunchConfiguration'
    ClosestToNextInstanceHour = 'ClosestToNextInstanceHour'

I can then use this like so:

    template.add_resource(AutoScalingGroup(
        'AutoScalingGroup',
        VPCZoneIdentifier=FindInMap(
            region_map, Ref('AWS::Region'), 'InstanceSubnetIds',
        ),
        LaunchConfigurationName=Ref(launch_config),
        AvailabilityZones=FindInMap(
            region_map, Ref('AWS::Region'), 'AvailabilityZones',
        ),
        MinSize=Ref('MinSize'),
        MaxSize=Ref('MaxSize'),
        # time until the asg begins scaling instances based on cpu usage.
        # reduces false scaling alarms while bootstrapping the nodes.
        HealthCheckGracePeriod=300,
        DesiredCapacity=Ref('DesiredCapacity'),
        Tags=[
            asc.Tag('chef:role', Ref('ChefRole'), True),
            asc.Tag('chef:environment', Ref('ChefEnv'), True),
        ],
        NotificationConfiguration=asc.NotificationConfiguration(
            TopicARN=Ref(alarmtopic),
            NotificationTypes=[
                asc.EC2_INSTANCE_LAUNCH,
                asc.EC2_INSTANCE_LAUNCH_ERROR,
                asc.EC2_INSTANCE_TERMINATE,
                asc.EC2_INSTANCE_TERMINATE_ERROR,
            ]
        ),
        TerminationPolicies=[TerminationPolicies.NewestInstance],
    ))

(Note the last line)

This seems pretty basic to me, if I submit a pull-request similar to this what else would need to be done to consider this completed?

I can confirm that it's being set, when I grep my asgs using AWS_DEFAULT_REGION=us-west-1 aws autoscaling describe-auto-scaling-groups | grep -i terminat -A3 I see

...
            "TerminationPolicies": [
                "Default"
            ], 
            "LaunchConfigurationName": "bpxy-prod-xbn27c-LaunchConfiguration-QZZJUK5IT41W", 
--
            "TerminationPolicies": [
                "NewestInstance"
            ], 
            "LaunchConfigurationName": "bwrk-integration-prod-zfwgyf-LaunchConfiguration-B56XEYXA4JXO", 
--
            "TerminationPolicies": [
                "Default"
            ], 
...

HealthyThreshold / integer_range() param in HealthCheck construct (in ELB) returns null for valid value

When you put a legitimate value into "HealthyThreshold" for an ELB, the resultant JSON output returns null. This attribute is the only one in the code using integer_range() data type. This is using the current bleeding edge git code.

Example code:

#!/usr/bin/env python

from troposphere import Base64, FindInMap, GetAtt, GetAZs, Select, Join
from troposphere import Parameter, Output, Ref, Template
import troposphere.elasticloadbalancing as elb

template = Template()

default_healthcheck = elb.HealthCheck(
    HealthyThreshold="5",
    Interval="60",
    Target="HTTP:80/index.html",
    Timeout="10",
    UnhealthyThreshold="3"
)

default_port80_listener = elb.Listener(
  LoadBalancerPort="80",
  InstancePort="80",
  Protocol="HTTP"
)

my_elb = template.add_resource(elb.LoadBalancer(
  "MyElb",
  Subnets=[],
  SecurityGroups=[],
  HealthCheck=default_healthcheck,
  Listeners=[ default_port80_listener ]
))

print(template.to_json())

Resulting output fragment:

{
    "Resources": {
        "MyElb": {
            "Properties": {
                "HealthCheck": {
                    "HealthyThreshold": null,
                    "Interval": 60,
                    "Target": "HTTP:80/index.html",

I'm sure it's something straightforward in validators.py but my python-fu is a bit rusty so I'm raising the issue and may suggest a fix later.

License

Hi Markpeek, have you considered making the troposphere license MIT: http://opensource.org/licenses/MIT

It looks like your license has the same intent (apologies if i'm reading it wrong), but it might make usage/contribution easier for organisations who get nervous about this kind of thing :-)

Thanks,

Tom

Question about release

Hey,

I had a couple questions about release. I originally got this library from PyPI, and it's at 0.3.4. I don't see corresponding tag in the git repo. Any chance that the versions could be tagged? It'd be nice to be able to use the pip install git support to fetch from a tag instead of a sha for released versions.

Secondly, is there any chance that a release can be cut? I would really like to use the NetworkInterfaceAttachment objects, which were added after the 0.3.4 release. Right now I am using it from the HEAD, but it's be nice to have a release. If there are any blockers, what are they? Maybe I can help.

This is a nice little library. Thanks for making it available.

Thanks,
wt

VPC_EC2_Instance example issue

Line 112: 'NetworkInterfaceId=Ref(eth0)', is getting a null value set in the template for the Ref lookup:

"NetworkInterfaces": [
{
"Ref": null

Not sure if the changes from 12/22 modified the way to get through the 'NetworkInterfaceProperty' to the 'NetworkInterface' to resolve the reference.

Is it possible to use Ref with VpcID in EC2 SecurityGroup?

I'm trying to make a Cloudformation template that allows the VpcID to be provided at runtime as a parameter. This is then used when creating a SecurityGroup.

The AWS Documentation says that SecurityGroup accepts VpcID as a string, but it also accepts using Ref.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html#cfn-ec2-securitygroup-vpcid

If I try to use Ref in Troposphere like so:
VpcId = Ref(myVPC)
it returns:
VpcId = Ref(myVPC) File "C:\Python27\lib\site-packages\troposphere\__init__.py", line 32, in __init__ if name and not valid_names.match(name): TypeError: expected string or buffer

If I try to trick it and put:
VpcId = '{ "Ref" : "myVPC" }'
it outputs:
"VpcId": "{ \"Ref\" : \"myVPC\" }"
when I want:
"VpcId": { "Ref" : "myVPC" }

Am I doing it wrong or if not, is there any other workaround that I'm missing here? I'm only slowly picking up on Python, so if there's a Pythony workaround for outputting the Ref, I'll be happy to try it.

Invalid json generated with SecurityGroupIngress

Ref: https://s3-us-west-2.amazonaws.com/cloudformation-templates-us-west-2/EC2InstanceWithSecurityGroupSample.template

Invalid format generated:

"SecurityGroupIngress": [
                    {
                        "Properties": {
                            "CidrIp": "0.0.0.0/0",
                            "FromPort": "0",
                            "IpProtocol": "-1",
                            "ToPort": "65535"
                        },
                        "Type": "AWS::EC2::SecurityGroupIngress"
                    }
                ]

With the above template AWS will complain:

Encountered unsupported property Type

Correct format:

"SecurityGroupIngress": [
                    {
                        "CidrIp": "0.0.0.0/0",
                        "FromPort": "0",
                        "IpProtocol": "-1",
                        "ToPort": "65535"
                    }
                ]

Getting numerous errors in cfn2py script

Would there be value in loading my json here and letting someone work through specific issues? Is there currently working going on with cfn2py ?

Here's the first error from running the script on the json file:

from troposphere.route53 import RecordSetGroup
from troposphere.elasticloadbalancing import LoadBalancer
from troposphere.cloudwatch import Alarm
from troposphere.ec2 import SecurityGroup
from troposphere.autoscaling import LaunchConfiguration
from troposphere.autoscaling import AutoScalingGroup

t = Template()

t.add_version("2010-09-09")

t.add_description("""\
experts-dev2-experts - Shows experts and their topics""")
devexpertsELBDNSARecord0 = t.add_resource(RecordSetGroup(
    "devexpertsELBDNSARecord0",
    HostedZoneName="inpwrd.net.",
    Comment="Alias targeted to devexpertsELB ELB.",
Traceback (most recent call last):
  File "/usr/bin/cfn2py", line 229, in <module>
    globals()["do_" + s.lower()](d)
  File "/usr/bin/cfn2py", line 128, in do_resources
    print '    %s=%s,' % (pk, output_value(pv))
  File "/usr/bin/cfn2py", line 178, in output_value
    return "[" + ", ".join(out) + "]"
TypeError: sequence item 0: expected string, NoneType found

Adding OpenStack native types

We've just started using OpenStack's Heat API which supports CloudFormation templates and has compatibility for AWS CloudFormation types (e.g. AutoScalingGroups, ELB's, etc).

Over time, we've started switching to the native OpenStack equivalents and I've been adding them to my fork of troposphere. It's not complete, but I have all the basic types.

I haven't looked at tests or anything like that at this stage, but would you be interested in accepting them into troposphere master?

CloudFront DistributionConfig, CacheBehavior and DefaultCacheBehavior

Policytypes example

I've been trying to create a AWS::IAM::Role for the following template:

        "DescribeEc2AndStackRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Statement": [ {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": [ "ec2.amazonaws.com" ]
                        },
                        "Action": [ "sts:AssumeRole" ]
                    } ]
                },
                "Path": "/",
                "Policies": [
                {
                    "PolicyName": "describestacks",
                    "PolicyDocument": {
                        "Statement": [ {
                            "Effect": "Allow",
                            "Action": "cloudformation:DescribeStacks",
                            "Resource": "*"
                        } ]
                    }
                },
                {
                    "PolicyName": "describeec2",
                    "PolicyDocument": {
                        "Statement": [ {
                            "Effect": "Allow",
                            "Action": "EC2:Describe*",
                            "Resource": "*"
                        } ]
                    }
                }
                ]
            }
        },

From reading the code I need to pass a dictionary of Policies to AssumeRolePolicyDocument? Have you got any examples of how to do that?

Thanks,
Pierre

cfn2py dies with bool value

Running latest version of cfn2py from master, I am getting the following error:

AclEgressAll = t.add_resource(NetworkAclEntry(
    "AclEgressAll",
    NetworkAclId=Ref(VpcAcl),
    RuleNumber="100",
    Protocol="-1",
Traceback (most recent call last):
  File "./cfn2py", line 227, in <module>
    globals()["do_" + s.lower()](d)
  File "./cfn2py", line 128, in do_resources
    print '    %s=%s,' % (pk, output_value(pv))
  File "./cfn2py", line 179, in output_value
    for fk, fv in v.items():
AttributeError: 'bool' object has no attribute 'items'

from the source JSON

    "AclEgressAll" : {
      "Type" : "AWS::EC2::NetworkAclEntry",
      "Properties" : {
        "CidrBlock" : "0.0.0.0/0",
        "Egress" : true,
        "Protocol" : "-1",
        "RuleAction" : "allow",
        "RuleNumber" : "100",
        "NetworkAclId" : {
          "Ref" : "VpcAcl"
        }
      }
    },

Please let me know if you need more information.

RecordSets in Route53 not formatted correctly

It seems that the formatting for RecordSets in Route53 is not correct. While trying to set up round-robin in Route53 between two instances the Cloudformation template created does not have the RecordSets objects correctly configured in the list within the RecordSetGroup.

The issue is highlighted here: https://forums.aws.amazon.com/thread.jspa?threadID=117678#

The troposphere code generates a template in the format of the poster, where is should generate a template in the format of the answer. I have tested the template generated by the example script - https://github.com/cloudtools/troposphere/blob/master/examples/Route53_RoundRobin.py - and generates the same incorrect template and fails.

This is likely to the intricacy of Cloudformation not requiring the 'Properties' in a RecordSet list and troposphere creating the list from the same resources as for the single records.

Thanks.

cfn2py failure

$ curl https://raw.githubusercontent.com/thefactory/cloudformation-zookeeper/master/zookeeper-vpc.json
$ cfn2py zookeeper-vpc.json 

from troposphere import Base64, FindInMap, GetAtt, Join, Output
from troposphere import Parameter, Ref, Tags, Template
from troposphere.cloudfront import Distribution, DistributionConfig
from troposphere.cloudfront import Origin, DefaultCacheBehavior
from troposphere.ec2 import PortRange
from troposphere.elasticloadbalancing import LoadBalancer
from troposphere.ec2 import SecurityGroup
from troposphere.iam import User
from troposphere.autoscaling import LaunchConfiguration
from troposphere.ec2 import SecurityGroupIngress
from troposphere.iam import AccessKey
from troposphere.autoscaling import AutoScalingGroup
from troposphere.cloudformation import WaitConditionHandle


t = Template()

t.add_version("2010-09-09")

t.add_description("""\
Launches an Exhibitor-managed ZooKeeper cluster""")
Subnets = t.add_parameter(Parameter(
    "Subnets",
    Type="CommaDelimitedList",
    Description="List of VPC subnet IDs for the cluster. Note: must match up with the passed AvailabilityZones.",
))

ExhibitorS3Prefix = t.add_parameter(Parameter(
    "ExhibitorS3Prefix",
    Type="String",
    Description="Key prefix for S3 backups. Should be unique per S3 bucket per cluster",
))

ExhibitorS3Region = t.add_parameter(Parameter(
    "ExhibitorS3Region",
    Type="String",
    Description="Region for Exhibitor backups of ZK configs",
))

ExhibitorS3Bucket = t.add_parameter(Parameter(
    "ExhibitorS3Bucket",
    Type="String",
    Description="Bucket for Exhibitor backups of ZK configs",
))

DockerImage = t.add_parameter(Parameter(
    "DockerImage",
    Default="thefactory/zookeeper-exhibitor:latest",
    Type="String",
    Description="Path of the ZK+Exhibitor Docker image (format: '[<registry>[:<port>]/]<repository>:<version>')",
))

VpcId = t.add_parameter(Parameter(
    "VpcId",
    Type="String",
    Description="VPC associated with the provided subnets",
))

ClusterSize = t.add_parameter(Parameter(
    "ClusterSize",
    Default="3",
    Type="Number",
    Description="Number of nodes to launch",
))

KeyName = t.add_parameter(Parameter(
    "KeyName",
    Type="String",
    Description="Name of an existing EC2 keypair to enable SSH access to the instances",
))

AdminSecurityGroup = t.add_parameter(Parameter(
    "AdminSecurityGroup",
    Type="String",
    Description="Existing security group that should be granted administrative access to ZooKeeper (e.g., 'sg-123456')",
))

AvailabilityZones = t.add_parameter(Parameter(
    "AvailabilityZones",
    Default="",
    Type="CommaDelimitedList",
    Description="(Optional) If passed, only launch nodes in these AZs (e.g., 'us-east-1a,us-east-1b'). Note: these must match up with the passed Subnets.",
))

InstanceType = t.add_parameter(Parameter(
    "InstanceType",
    Default="m1.small",
    ConstraintDescription="must be a valid EC2 instance type.",
    Type="String",
    Description="EC2 instance type",
    AllowedValues="[u't1.micro', u'm1.small', u'm1.medium', u'm1.large', u'm1.xlarge', u'm2.xlarge', u'm2.2xlarge', u'm2.4xlarge', u'm3.xlarge', u'm3.2xlarge', u'c1.medium', u'c1.xlarge', u'cc1.4xlarge', u'cc2.8xlarge', u'cg1.4xlarge']",
))

t.add_mapping("RegionMap",
{u'ap-northeast-1': {u'AMI': u'ami-a13876a0'},
 u'ap-southeast-1': {u'AMI': u'ami-1695c944'},
 u'ap-southeast-2': {u'AMI': u'ami-5993f663'},
 u'eu-west-1': {u'AMI': u'ami-27aa6450'},
 u'sa-east-1': {u'AMI': u'ami-0d18b410'},
 u'us-east-1': {u'AMI': u'ami-94a54efc'},
 u'us-west-1': {u'AMI': u'ami-02141347'},
 u'us-west-2': {u'AMI': u'ami-2598ea15'}}
)

ElasticLoadBalancer = t.add_resource(LoadBalancer(
    "ElasticLoadBalancer",
    Subnets=Ref(Subnets),
Traceback (most recent call last):
  File "/usr/local/bin/cfn2py", line 5, in <module>
    pkg_resources.run_script('troposphere==0.5.0', 'cfn2py')
  File "build/bdist.macosx-10.9-intel/egg/pkg_resources.py", line 487, in run_script
    ns.clear()
  File "build/bdist.macosx-10.9-intel/egg/pkg_resources.py", line 1344, in run_script
    "resource_filename() only supported for .egg, not .zip"
  File "/Library/Python/2.7/site-packages/troposphere-0.5.0-py2.7.egg/EGG-INFO/scripts/cfn2py", line 229, in <module>

  File "/Library/Python/2.7/site-packages/troposphere-0.5.0-py2.7.egg/EGG-INFO/scripts/cfn2py", line 128, in do_resources

  File "/Library/Python/2.7/site-packages/troposphere-0.5.0-py2.7.egg/EGG-INFO/scripts/cfn2py", line 178, in output_value

TypeError: sequence item 0: expected string, NoneType found

Autoscaling: unable to use Refs for MaxSize

We want to use refs for MaxSize so that we can deploy to different environments with different sizes, but autoscaling.py checks for integerness on that.

./env/lib/python2.7/site-packages/troposphere/autoscaling.py
8c8
< import pdb

---
> import inspect
58,62c58,67
<             if int(update_policy.MinInstancesInService) >= int(self.MaxSize):
<                 raise ValueError(
<                     "The UpdatePolicy attribute "
<                     "MinInstancesInService must be less than the "
<                     "autoscaling group's MaxSize")

---
>             try:
>                 if int(update_policy.MinInstancesInService) >= int(self.MaxSize):
>                     raise ValueError(
>                         "The UpdatePolicy attribute "
>                         "MinInstancesInService must be less than the "
>                         "autoscaling group's MaxSize")
>             except TypeError, e:
>                 # this is almost certainly that we are using a Ref for these values
>                 # instead of the integers expected here.
>                 return True

Not sure if you're accepting patches :S

cfn2py dies while processing SecurityGroupEgress

It would seem I have the best CF template ever for testing cfn2py.

The script is now returning this error:

NatSecurityGroup = t.add_resource(SecurityGroup(
    "NatSecurityGroup",
    VpcId=Ref(MyVpc),
    GroupDescription="NAT VPC security group",
Traceback (most recent call last):
  File "./cfn2py", line 229, in <module>
    globals()["do_" + s.lower()](d)
  File "./cfn2py", line 128, in do_resources
    print '    %s=%s,' % (pk, output_value(pv))
  File "./cfn2py", line 178, in output_value
    return "[" + ", ".join(out) + "]"
TypeError: sequence item 0: expected string, NoneType found

with the following as the input template snipped

    "NatSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "NAT VPC security group",
        "VpcId" : {
          "Ref" : "MyVpc"
        },
        "SecurityGroupEgress" : [ {
          "IpProtocol" : "-1",
          "CidrIp" : "0.0.0.0/0"
        } ]
      }
    },

Please let me know if you need any more information.

Elastic Load Balancer acts as if there is not healthcheck defined

As I started building the loadbalancer section of troposphere, I got an error

Traceback (most recent call last):
File "experts.py", line 61, in
elb.HealthCheck = HealthCheck(Target = "TCP:80",
NameError: name 'HealthCheck' is not defined

Here's that section of the code:

elb = elasticloadbalancing.LoadBalancer("devexpertsELB")
elb.AvailabilityZones = [ "us-east-1a", "us-east-1e"]

elb.HealthCheck = HealthCheck(Target = "TCP:80",
HealthyThreshold = "5",
UnhealthyThreshold = "2",
Interval = "10",
Timeout = "8"
)

elb.Listeners = [
Listener(LoadBalancerPort = "80",
InstancePort = "80",
Protocol = "HTTP"
),
Listener(LoadBalancerPort = "443",
InstancePort = "443",
Protocol = "HTTPS",
InstanceProtocol = "HTTPS",
SSLCertificateId = "arn:aws:iam::283551568899:server-certificate/wildcard_inpwrd_net"
)]
t.add_resource(elb)

I get the same error on the listener too if I remove the health check.

I looked at elasticloadbalancer.py and I see that the HealthCheck and Listener are both defined so I'm not clear as to why it doesn't work.

iam.User class "Group" prop is incomplete

Trying to create a user who is in a particular group with something like this:

user = cft.add_resource(
    iam.User(
        user_name,
        Groups=Ref(group)
    )
)

Results in this JSON:

        "JoeUser": {
            "Properties": {
                "Groups": {
                    "Ref": "Admins"
                }
            }, 
            "Type": "AWS::IAM::User"
        }

Which fails during CFT launch due to an invalid Groups property ("Groups" should be a list per the AWS CFT documentation AND Troposphere conforms to that standard except that it requires the property to be of type [troposphere.iam.Group]...

{'Groups': ([troposphere.iam.Group], False),
 'LoginProfile': (troposphere.iam.LoginProfile, False),
 'Path': (basestring, False),
 'Policies': ([troposphere.iam.Policy], False)}

The problem is that actually giving it a list of troposphere.iam.Group objects will result in a group object (i.e. Type:AWS:IAM:Group) being defined in the User object instead of a list of group names as required per: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-user.html#cfn-iam-user-groups). Here is an example of the JSON generated by actually providing a list of a single iam.Group class object...

        "JoeUser": {
            "Properties": {
                "Groups": [
                    {
                        "Properties": {
                            "Policies": [
                                {
                                    "PolicyDocument": {
                                        "Statement": [
                                            {
                                                "Action": [
                                                    "*"
                                                ], 
                                                "Effect": "Allow", 
                                                "Resource": "*"
                                            }
                                        ]
                                    }, 
                                    "PolicyName": "AdminPolicy"
                                }
                            ]
                        }, 
                        "Type": "AWS::IAM::Group"
                    }
                ]
            }, 
            "Type": "AWS::IAM::User"
        }

What it should require is a list of Refs or basestrings I would think. Just like the iam.Policy class...

class PolicyProps():
    props = {
        'Groups': ([basestring, Ref], False),
        'PolicyDocument': (policytypes, True),
        'PolicyName': (basestring, True),
        'Roles': ([basestring, Ref], False),
        'Users': ([basestring, Ref], False),
    }

Or am I missing something here?
Thanks! and awesome project BTW.

Reverse engineer a cloudformation json into python

I'd love to use this library, but I have a rather large existing cloudformation json file setup, I'd like to reverse engineer an existing json file into a python script.

Are there any plans to write this feature?

Sorry I raised the issue as I couldn't find another mechanism to ask.

ec2.NetworkInterfaceProperty.GroupSet can be Ref()

Using troposphere I got this result using a Ref() for SG referencing:

TypeError: GroupSet is <class 'troposphere.Ref'>, expected [<type 'basestring'>]

According to AWS own examples there can be a Ref():

    "EC2Host" : {
      "Type" : "AWS::EC2::Instance",
      "DependsOn" : "GatewayToInternet",
      "Properties" : {
        "InstanceType" : { "Ref" : "EC2InstanceType" },
        "KeyName"  : { "Ref" : "KeyName" },
        "ImageId"  : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "EC2InstanceType" }, "Arch" ] } ] },
        "NetworkInterfaces" : [{
          "GroupSet"                 : [{ "Ref" : "EC2SecurityGroup" }],
          "AssociatePublicIpAddress" : "true",
          "DeviceIndex"              : "0",
          "DeleteOnTermination"      : "true",
          "SubnetId"                 : { "Ref" : "PublicSubnet" }
        }]
      }
    },

Taken from https://s3.amazonaws.com/cloudformation-templates-us-east-1/VPC_With_PublicIPs_And_DNS.template

Integer TTL Issue with route53.RecordSet

If you pass an integer for the TTL parameter to the route53.RecordSet class, the TTL will be output as an integer in the CF template. This TTL will then be ignored when the record is created as CF expects the parameter to be a string.

It would be nice and potentially save some confusion if this parameter could be explicitly converted to a string before the template is generated.

Workaround for missing AWS resource types?

Thanks for a very useful package. As mentioned in the docs, there are three AWS resource types still on the to-do list. I am particularly interested in AWS::CloudFormation::Init. Can you suggest a workaround for including these resources using troposphere as it stands or is this not possible yet? Thanks again.

Create .py from template file?

This is wishlist item, not a bug. If I already have a collection of json CF templates, but I really like the python source syntax as it's far more readable, it would be nice if there were a way to generate the python source from an existing json template.

Allow AWSObject instances to be assigned to properties

The current pattern in troposphere is something like:

template.add_resource(SomeResource("ResourceName", VpcId=Ref(vpc_instance)))

Almost any time you are going to add a local variable containing an AWSObject as a property to another object, you are likely going to be adding a Ref

It seems to me that the 'Ref' construct in cfn JSON is a way of handling variables in JSON. So while the template is existing logically in Python - why not let these references exist as regular python references.

I have an initial WIP here which converts to Ref() on setitem:

https://github.com/ptone/troposphere/compare/assume-refs?expand=1

But I'd actually like to see the resolving of this into a Ref, come later, right before serialization to json.

Maybe templates can have a some sort of pre to_json hook that can do this resolving?

cfn2py dies when it gets to tags

I have a template that I am converting to Python and the cfn2py script dies with this error:

VpcAcl = t.add_resource(NetworkAcl(
    "VpcAcl",
    VpcId=Ref("MyVpc"),
Traceback (most recent call last):
  File "/usr/local/share/python/cfn2py", line 206, in <module>
    globals()["do_" + s.lower()](d)
  File "/usr/local/share/python/cfn2py", line 112, in do_resources
    print '    %s=%s,' % (pk, output_value(pv))
  File "/usr/local/share/python/cfn2py", line 158, in output_value
    for fk, fv in v.items():
AttributeError: 'list' object has no attribute 'items'

The part of the template it is dying with is here:

    "VpcAcl" : {
      "Type" : "AWS::EC2::NetworkAcl",
      "Properties" : {
        "VpcId" : {
          "Ref" : "MyVpc"
        },
        "Tags" : [ {
            "Key" : "Name",
            "Value" : "VPC ACL"
          }, {
            "Key" : "Environment",
            "Value" : {
              "Ref" : "EnvironmentName"
            }
        } ]
      }
    },

If I delete the Tags section from the source template, things go smoothly.

If you need more information, please ask.

Fix 51 prevents me formatting single records correctly

Comment duplicated from : abbb86d

I can't describe my ComponentDNS as just a RecordSet with component/properties etc.. This I either have to back out my fix or use a group which we haven't been doing.. Is that intended or an accidental consequence..

sorry to raise this as an issue if it isn't

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.