Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/gh 118 aws virtual network #624

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 83 additions & 1 deletion data/tosca/yorc-aws-types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ tosca_definitions_version: yorc_tosca_simple_yaml_1_0
metadata:
template_name: yorc-aws-types
template_author: yorc
template_version: 1.1.0
template_version: 1.2.0

imports:
- yorc: <yorc-types.yml>
Expand Down Expand Up @@ -101,4 +101,86 @@ node_types:
required: false
default: false

yorc.nodes.aws.VPC:
derived_from: tosca.nodes.Network
# See https://www.terraform.io/docs/providers/aws/r/vpc.html
properties:
cidr_block:
type: string
required: true
instance_tenancy:
type: string
description: >
You can run instances in your VPC on single-tenant, dedicated hardware.
Select Dedicated to ensure that instances launched in this VPC are dedicated tenancy instances, regardless of the tenancy attribute specified at launch.
Select Default to ensure that instances launched in this VPC use the tenancy attribute specified at launch
default: default
constraints :
- valid_values: [default, dedicated]
enable_dns_support:
type: boolean
description: A boolean flag to enable/disable DNS support in the VPC. Defaults true.
default: true
required: false
enable_dns_hostnames:
type: boolean
default: false
description : A boolean flag to enable/disable DNS hostnames in the VPC. Defaults false.
required: false
enable_classiclink:
type: boolean
default: false
description: A boolean flag to enable/disable ClassicLink for the VPC. Only valid in regions and accounts that support EC2 Classic.
required: false
enable_classiclink_dns_support:
type: boolean
required: false
description: A boolean flag to enable/disable ClassicLink DNS Support for the VPC. Only valid in regions and accounts that support EC2 Classic
assign_generated_ipv6_cidr_block:
type: boolean
required: false
description: Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block.
tags:
type: map
description: A mapping of tags to assign to the resource.
required: false
entry_schema:
type: string

yorc.nodes.aws.Subnet:
derived_from: tosca.nodes.Network
# See : https://www.terraform.io/docs/providers/aws/r/subnet.html
properties:
availability_zone:
type: string
required: false
description: The AZ for the subnet
availability_zone_id:
type: string
required: false
description: The AZ for the subnet
HildericSB marked this conversation as resolved.
Show resolved Hide resolved
cidr_block:
type: string
required: true
ipv6_cidr_block :
type: string
required: false
HildericSB marked this conversation as resolved.
Show resolved Hide resolved
map_public_ip_on_launch:
type: boolean
required: false
description: The AZ for the subnet
HildericSB marked this conversation as resolved.
Show resolved Hide resolved
assign_ipv6_address_on_creation:
type: boolean
required: false
description: >
Specify true to indicate that network interfaces created in the specified subnet should be assigned an IPv6 address
vpc_id:
type: string
required: true
tags:
type: map
description: A mapping of tags to assign to the resource.
required: false
entry_schema:
type: string

48 changes: 48 additions & 0 deletions prov/terraform/aws/aws_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,54 @@ func (g *awsGenerator) generateAWSInstance(ctx context.Context, cfg config.Confi
if placementGroup != nil {
instance.PlacementGroup = placementGroup.RawString()
}

// Network Interfaces
hasNetwork, _, err := deployments.HasAnyRequirementFromNodeType(ctx, deploymentID, nodeName, "network", "yorc.nodes.aws.Subnet")
if err != nil {
return err
}
if hasNetwork {
networkRequirements, err := deployments.GetRequirementsByTypeForNode(ctx, deploymentID, nodeName, "network")
if err != nil {
return err
}

// Start at 1, (0 reserved for the default network interface)
i := 0
for _, networkReq := range networkRequirements {
networkInterface := &NetworkInterface{}
networkInterface.SubnetID, err = deployments.LookupInstanceAttributeValue(ctx, deploymentID, networkReq.RequirementAssignment.Node, instanceName, "subnet_id")
if err != nil {
return err
}
networkInterface.SecurityGroups = instance.SecurityGroups
name := strings.ToLower("network-inteface-" + strconv.Itoa(i))
name = strings.Replace(strings.ToLower(name), "_", "-", -1)

// First interface will be considered as default one
if i == 0 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identical blocks of code found in 2 locations. Consider refactoring.

instance.NetworkInterface = map[string]string{
"network_interface_id": "${aws_network_interface." + name + ".id}",
"device_index": strconv.Itoa(i),
}
} else {
// Others interfaces are considered attachment
networkInterface.Attachment = map[string]string{
"instance": "${aws_instance." + instance.Tags.Name + ".id}",
"device_index": strconv.Itoa(i),
}
}

commons.AddResource(infrastructure, "aws_network_interface", name, networkInterface)

i++
}

// No security groups on instance level when defining customs ENI
// (So the instance will have be in the default security groups on creation)
instance.SecurityGroups = nil
}

// Add the AWS instance
commons.AddResource(infrastructure, "aws_instance", instance.Tags.Name, &instance)

Expand Down
30 changes: 30 additions & 0 deletions prov/terraform/aws/aws_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,33 @@ func testSimpleAWSInstanceWithPersistentDisk(t *testing.T, cfg config.Configurat
assert.Equal(t, "/dev/sdf", attachedDisk.DeviceName)

}

func simpleAWSInstanceWithVPCandSubnet(t *testing.T, cfg config.Configuration, srv *testutil.TestServer) {
t.Parallel()

deploymentID := loadTestYaml(t)
g := awsGenerator{}
infrastructure := commons.Infrastructure{}
ctx := context.Background()
env := make([]string, 0)
outputs := make(map[string]string)

srv.PopulateKV(t, map[string][]byte{
path.Join(consulutil.DeploymentKVPrefix, deploymentID+"/topology/nodes/Network_Subnet/type"): []byte("yorc.nodes.aws.Subnet"),
path.Join(consulutil.DeploymentKVPrefix, deploymentID+"/topology/instances/Network_Subnet/0/attributes/subnet_id"): []byte("subnet_id"),
})

err := g.generateAWSInstance(ctx, cfg, deploymentID, "AWS_Compute", "0", &infrastructure, outputs, &env)
require.Nil(t, err)
require.Len(t, infrastructure.Resource["aws_instance"], 1)

instancesMap := infrastructure.Resource["aws_instance"].(map[string]interface{})
require.Contains(t, instancesMap, "AWS_Compute-0")

compute, ok := instancesMap["AWS_Compute-0"].(*ComputeInstance)
require.True(t, ok, "%s is not a ComputeInstance", "AWS_Compute-0")

assert.Equal(t, "${aws_network_interface.network-inteface-0.id}", compute.NetworkInterface["network_interface_id"], "Subnetwork is not retrieved")
assert.Equal(t, "0", compute.NetworkInterface["device_index"], "Subnetwork is not retrieved")

}
10 changes: 9 additions & 1 deletion prov/terraform/aws/consul_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"testing"

"github.com/stretchr/testify/require"

"github.com/ystia/yorc/v4/locations"
"github.com/ystia/yorc/v4/testutil"
)
Expand Down Expand Up @@ -64,6 +63,9 @@ func TestRunConsulAWSPackageTests(t *testing.T) {
t.Run("simpleAWSInstanceWithMalformedEIP", func(t *testing.T) {
testSimpleAWSInstanceWithMalformedEIP(t, cfg)
})
t.Run("simpleAWSInstanceWithVPCandSubnet", func(t *testing.T) {
simpleAWSInstanceWithVPCandSubnet(t, cfg, srv)
})
t.Run("generateTerraformInfraForAWSNode", func(t *testing.T) {
testGenerateTerraformInfraForAWSNode(t, cfg, locationMgr)
})
Expand All @@ -76,5 +78,11 @@ func TestRunConsulAWSPackageTests(t *testing.T) {
t.Run("simpleAWSInstanceWithPersistentDisk", func(t *testing.T) {
testSimpleAWSInstanceWithPersistentDisk(t, cfg, srv)
})
t.Run("simpleVPC", func(t *testing.T) {
testSimpleVPC(t, cfg)
})
t.Run("simpleSubnet", func(t *testing.T) {
testSimpleSubnet(t, srv, cfg)
})
})
}
11 changes: 11 additions & 0 deletions prov/terraform/aws/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ func (g *awsGenerator) generateInstances(ctx context.Context, cfg config.Configu
if err != nil {
return err
}
case "yorc.nodes.aws.VPC":
err = g.generateVPC(ctx, *nodeParams, instanceName, outputs)
if err != nil {
return err
}

case "yorc.nodes.aws.Subnet":
err = g.generateSubnet(ctx, *nodeParams, instanceName, outputs)
if err != nil {
return err
}
default:
return errors.Errorf("Unsupported node type '%s' for node '%s' in deployment '%s'", nodeType, nodeParams.nodeName, nodeParams.deploymentID)
}
Expand Down
55 changes: 46 additions & 9 deletions prov/terraform/aws/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ package aws

// A ComputeInstance represent an AWS compute
type ComputeInstance struct {
ImageID string `json:"ami,omitempty"`
InstanceType string `json:"instance_type,omitempty"`
AvailabilityZone string `json:"availability_zone,omitempty"`
PlacementGroup string `json:"placement_group,omitempty"`
SecurityGroups []string `json:"security_groups,omitempty"`
KeyName string `json:"key_name,omitempty"`
Tags Tags `json:"tags,omitempty"`
ElasticIps []string `json:"-"`
RootBlockDevice BlockDevice `json:"root_block_device,omitempty"`
ImageID string `json:"ami,omitempty"`
InstanceType string `json:"instance_type,omitempty"`
AvailabilityZone string `json:"availability_zone,omitempty"`
PlacementGroup string `json:"placement_group,omitempty"`
SecurityGroups []string `json:"security_groups,omitempty"`
KeyName string `json:"key_name,omitempty"`
Tags Tags `json:"tags,omitempty"`
ElasticIps []string `json:"-"`
RootBlockDevice BlockDevice `json:"root_block_device,omitempty"`
NetworkInterface map[string]string `json:"network_interface,omitempty"`

Provisioners map[string]interface{} `json:"provisioner,omitempty"`
}
Expand Down Expand Up @@ -71,3 +72,39 @@ type VolumeAttachment struct {
InstanceID string `json:"instance_id,omitempty"`
VolumeID string `json:"volume_id,omitempty"`
}

// VPC represents a virtual private cloud
// see : https://www.terraform.io/docs/providers/aws/r/vpc.html
type VPC struct {
CidrBlock string `json:"cidr_block,omitempty"`
InstanceTenancy string `json:"instance_tenancy,omitempty"`
EnableDNSSupport bool `json:"enable_dns_support,omitempty"`
EnableDNSHostnames bool `json:"enable_dns_hostnames,omitempty"`
EnableClassiclink bool `json:"enable_classiclink,omitempty"`
EnableClassiclinkDNSSupport bool `json:"enable_classiclink_dns_support,omitempty"`
AssignGeneratedIpv6CidrBlock bool `json:"assign_generated_ipv6_cidr_block,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
}

// Subnet reprents a network in a VPC
// see : https://www.terraform.io/docs/providers/aws/r/subnet.html
type Subnet struct {
AvailabilityZone string `json:"availability_zone,omitempty"`
AvailabilityZoneID string `json:"availability_zone_id,omitempty"`
CidrBlock string `json:"cidr_block,omitempty"`
Ipv6CidrBlock string `json:"ipv6_cidr_block,omitempty"`
MapPublicIPOnLaunch bool `json:"map_public_ip_on_launch,omitempty"`
AssignIpv6AddressOnCreation bool `json:"assign_ipv6_address_on_creation,omitempty"`
VPCId string `json:"vpc_id,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
}

// NetworkInterface create an ENI (Elastic Network Interface)
// see : https://www.terraform.io/docs/providers/aws/r/network_interface.html#attachment
type NetworkInterface struct {
SubnetID string `json:"subnet_id,omitempty"`
Description string `json:"description,omitempty"`
PrivateIps string `json:"private_ips,omitempty"`
SecurityGroups []string `json:"security_groups,omitempty"`
Attachment map[string]string `json:"attachment,omitempty"`
}
59 changes: 59 additions & 0 deletions prov/terraform/aws/testdata/simpleAWSInstanceWithVPCandSubnet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
tosca_definitions_version: alien_dsl_2_0_0

metadata:
template_name: NetworkWithCustomSubnetsTest
template_version: 1.0
template_author: tester

description: ""

imports:
- <normative-types.yml>
- <yorc-google-types.yml>
- <yorc-types.yml>

topology_template:
node_templates:
Network_VPC:
type: yorc.nodes.aws.VPC
properties:
cidr_block: 10.0.0.0/16
AWS_Compute:
type: yorc.nodes.aws.Compute
properties:
image_id: "ami-16dffe73"
instance_type: "t2.micro"
key_name: "yorc-keypair"
security_groups: "yorc-securityGroup"
availability_zone: "us-east-2c"
placement_group: "myPlacement"
requirements:
- AWS_Compute_network:
type_requirement: network
node: Network_Subnet
capability: tosca.capabilities.Connectivity
relationship: tosca.relationships.Network
capabilities:
scalable:
properties:
min_instances: 1
max_instances: 1
default_instances: 1
endpoint:
properties:
secure: true
protocol: tcp
network_name: PRIVATE
initiator: source
credentials: {user: centos}
Network_Subnet:
type: yorc.nodes.aws.Subnet
properties:
cidr_block: 10.10.0.0/24
availability_zone: "us-east-2c"
requirements:
- VPC_Requirements:
type_requirement: dependency
node: Network_VPC
capability: tosca.capabilities.Node
relationship: tosca.relationships.DependsOn
29 changes: 29 additions & 0 deletions prov/terraform/aws/testdata/simpleSubnet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
tosca_definitions_version: alien_dsl_2_0_0

metadata:
template_name: VPC_creation_test
template_version: 1.0
template_author: tester

description: ""

imports:
- <normative-types.yml>
- <yorc-aws-types.yml>

topology_template:
node_templates:
Network_VPC:
type: yorc.nodes.aws.VPC
properties:
cidr_block: 10.0.0.0/16
Network_Subnet:
type: yorc.nodes.aws.Subnet
properties:
cidr_block: 10.0.0.0/24
requirements:
- Network_Subnet_Network_VPC:
type_requirement: dependency
node: Network_VPC
capability: tosca.capabilities.Node
relationship: tosca.relationships.DependsOn
Loading