Skip to content

Commit

Permalink
Merge branch 'duduklein-vpc-support' into develop
Browse files Browse the repository at this point in the history
Closes boto#1404

* duduklein-vpc-support:
  Remove whitespace, fix long line lengths
  Improve VPC and VPN support
  • Loading branch information
jamesls committed Apr 4, 2013
2 parents 906db3e + cf70440 commit 645f159
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 9 deletions.
21 changes: 19 additions & 2 deletions boto/vpc/vpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
Expand All @@ -28,15 +28,28 @@
class VPC(TaggedEC2Object):

def __init__(self, connection=None):
"""
Represents a VPC.
:ivar id: The unique ID of the VPC.
:ivar dhcp_options_id: The ID of the set of DHCP options you've associated with the VPC
(or default if the default options are associated with the VPC).
:ivar state: The current state of the VPC.
:ivar cidr_block: The CIDR block for the VPC.
:ivar is_default: Indicates whether the VPC is the default VPC.
:ivar instance_tenancy: The allowed tenancy of instances launched into the VPC.
"""
TaggedEC2Object.__init__(self, connection)
self.id = None
self.dhcp_options_id = None
self.state = None
self.cidr_block = None
self.is_default = None
self.instance_tenancy = None

def __repr__(self):
return 'VPC:%s' % self.id

def endElement(self, name, value, connection):
if name == 'vpcId':
self.id = value
Expand All @@ -46,6 +59,10 @@ def endElement(self, name, value, connection):
self.state = value
elif name == 'cidrBlock':
self.cidr_block = value
elif name == 'isDefault':
self.is_default = True if value == 'true' else False
elif name == 'instanceTenancy':
self.instance_tenancy = value
else:
setattr(self, name, value)

Expand Down
153 changes: 147 additions & 6 deletions boto/vpc/vpnconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,173 @@
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import boto
from datetime import datetime
from boto.resultset import ResultSet

"""
Represents a VPN Connectionn
"""

from boto.ec2.ec2object import EC2Object
from boto.ec2.ec2object import TaggedEC2Object

class VpnConnection(EC2Object):
class VpnConnectionOptions(object):
"""
Represents VPN connection options
:ivar static_routes_only: Indicates whether the VPN connection uses static
routes only. Static routes must be used for devices that don't support
BGP.
"""
def __init__(self, static_routes_only=None):
self.static_routes_only = static_routes_only

def __repr__(self):
return 'VpnConnectionOptions'

def startElement(self, name, attrs, connection):
pass

def endElement(self, name, value, connection):
if name == 'staticRoutesOnly':
self.static_routes_only = True if value == 'true' else False
else:
setattr(self, name, value)

class VpnStaticRoute(object):
"""
Represents a static route for a VPN connection.
:ivar destination_cidr_block: The CIDR block associated with the local
subnet of the customer data center.
:ivar source: Indicates how the routes were provided.
:ivar state: The current state of the static route.
"""
def __init__(self, destination_cidr_block=None, source=None, state=None):
self.destination_cidr_block = destination_cidr_block
self.source = source
self.available = state

def __repr__(self):
return 'VpnStaticRoute: %s' % self.destination_cidr_block

def startElement(self, name, attrs, connection):
pass

def endElement(self, name, value, connection):
if name == 'destinationCidrBlock':
self.destination_cidr_block = value
elif name == 'source':
self.source = value
elif name == 'state':
self.state = value
else:
setattr(self, name, value)

class VpnTunnel(object):
"""
Represents telemetry for a VPN tunnel
:ivar outside_ip_address: The Internet-routable IP address of the
virtual private gateway's outside interface.
:ivar status: The status of the VPN tunnel. Valid values: UP | DOWN
:ivar last_status_change: The date and time of the last change in status.
:ivar status_message: If an error occurs, a description of the error.
:ivar accepted_route_count: The number of accepted routes.
"""
def __init__(self, outside_ip_address=None, status=None, last_status_change=None,
status_message=None, accepted_route_count=None):
self.outside_ip_address = outside_ip_address
self.status = status
self.last_status_change = last_status_change
self.status_message = status_message
self.accepted_route_count = accepted_route_count

def __repr__(self):
return 'VpnTunnel: %s' % self.outside_ip_address

def startElement(self, name, attrs, connection):
pass

def endElement(self, name, value, connection):
if name == 'outsideIpAddress':
self.outside_ip_address = value
elif name == 'status':
self.status = value
elif name == 'lastStatusChange':
self.last_status_change = datetime.strptime(value,
'%Y-%m-%dT%H:%M:%S.%fZ')
elif name == 'statusMessage':
self.status_message = value
elif name == 'acceptedRouteCount':
try:
value = int(value)
except ValueError:
boto.log.warning('Error converting code (%s) to int' % value)
self.accepted_route_count = value
else:
setattr(self, name, value)

class VpnConnection(TaggedEC2Object):
"""
Represents a VPN Connection
:ivar id: The ID of the VPN connection.
:ivar state: The current state of the VPN connection.
Valid values: pending | available | deleting | deleted
:ivar customer_gateway_configuration: The configuration information for the
VPN connection's customer gateway (in the native XML format). This
element is always present in the
:class:`boto.vpc.VPCConnection.create_vpn_connection` response;
however, it's present in the
:class:`boto.vpc.VPCConnection.get_all_vpn_connections` response only
if the VPN connection is in the pending or available state.
:ivar type: The type of VPN connection (ipsec.1).
:ivar customer_gateway_id: The ID of the customer gateway at your end of
the VPN connection.
:ivar vpn_gateway_id: The ID of the virtual private gateway
at the AWS side of the VPN connection.
:ivar tunnels: A list of the vpn tunnels (always 2)
:ivar options: The option set describing the VPN connection.
:ivar static_routes: A list of static routes associated with a VPN
connection.
"""
def __init__(self, connection=None):
EC2Object.__init__(self, connection)
TaggedEC2Object.__init__(self, connection)
self.id = None
self.state = None
self.customer_gateway_configuration = None
self.type = None
self.customer_gateway_id = None
self.vpn_gateway_id = None
self.tunnels = []
self.options = None
self.static_routes = []

def __repr__(self):
return 'VpnConnection:%s' % self.id


def startElement(self, name, attrs, connection):
retval = super(VpnConnection, self).startElement(name, attrs, connection)
if retval is not None:
return retval
if name == 'vgwTelemetry':
self.tunnels = ResultSet([('item', VpnTunnel)])
return self.tunnels
elif name == 'routes':
self.static_routes = ResultSet([('item', VpnStaticRoute)])
return self.static_routes
elif name == 'options':
self.options = VpnConnectionOptions()
return self.options
return None

def endElement(self, name, value, connection):
if name == 'vpnConnectionId':
self.id = value
Expand All @@ -57,4 +199,3 @@ def endElement(self, name, value, connection):

def delete(self):
return self.connection.delete_vpn_connection(self.id)

11 changes: 10 additions & 1 deletion docs/source/vpc_tut.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,13 @@ Releasing an Elastic IP Attached to a VPC Instance
--------------------------------------------------

>>> ec2.connection.release_address(None, 'eipalloc-35cf685d')
>>>
>>>

To Get All VPN Connections
--------------------------
>>> vpns = c.get_all_vpn_connections()
>>> vpns[0].id
u'vpn-12ef67bv'
>>> tunnels = vpns[0].tunnels
>>> tunnels
[VpnTunnel: 177.12.34.56, VpnTunnel: 177.12.34.57]
Empty file added tests/unit/vpc/__init__.py
Empty file.
40 changes: 40 additions & 0 deletions tests/unit/vpc/test_vpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: UTF-8 -*-
from tests.unit import unittest
from tests.unit import AWSMockServiceTestCase

from boto.vpc import VPCConnection

DESCRIBE_VPCS = r'''<?xml version="1.0" encoding="UTF-8"?>
<DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2013-02-01/">
<requestId>623040d1-b51c-40bc-8080-93486f38d03d</requestId>
<vpcSet>
<item>
<vpcId>vpc-12345678</vpcId>
<state>available</state>
<cidrBlock>172.16.0.0/16</cidrBlock>
<dhcpOptionsId>dopt-12345678</dhcpOptionsId>
<instanceTenancy>default</instanceTenancy>
<isDefault>false</isDefault>
</item>
</vpcSet>
</DescribeVpcsResponse>'''

class TestDescriveVPCs(AWSMockServiceTestCase):

connection_class = VPCConnection

def default_body(self):
return DESCRIBE_VPCS

def test_get_vpcs(self):
self.set_http_response(status_code=200)

api_response = self.service_connection.get_all_vpcs()
self.assertEqual(len(api_response), 1)

vpc = api_response[0]
self.assertFalse(vpc.is_default)
self.assertEqual(vpc.instance_tenancy,'default')

if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit 645f159

Please sign in to comment.