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 23 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
170 changes: 168 additions & 2 deletions data/tosca/yorc-aws-types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,75 @@ 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>

data_types:
yorc.datatypes.aws.SubnetType:
derived_from: tosca.datatypes.Root
# 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 ID for the subnet
cidr_block:
type: string
required: true
ipv6_cidr_block :
type: string
required: false
description: The IPv6 network range for the subnet, in CIDR notation. The subnet size must use a /64 prefix length.
map_public_ip_on_launch:
type: boolean
required: false
description: Specify true to indicate that instances launched into the subnet should be assigned a public IP address.
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
tags:
type: map
description: A mapping of tags to assign to the resource.
required: false
entry_schema:
type: string

yorc.datatypes.aws.SecurityRuleType:
derived_from: tosca.datatypes.Root
# See : https://www.terraform.io/docs/providers/aws/r/subnet.html
properties:
from_port:
type: string
required: true
to_port:
type: string
required: true
protocol:
type: string
required: true

yorc.datatypes.aws.SecurityGroupType:
derived_from: tosca.datatypes.Root
# See : https://www.terraform.io/docs/providers/aws/r/subnet.html
properties:
name:
type: string
required: true
ingress:
type: yorc.datatypes.aws.SecurityRuleType
required: true
egress:
type: yorc.datatypes.aws.SecurityRuleType
required: true

node_types:
yorc.nodes.aws.Compute:
derived_from: yorc.nodes.Compute
Expand All @@ -29,7 +93,12 @@ node_types:
type: string
description: >
Comma-separated list of security groups to add to the Compute
required: true
required: false
subnet_id:
type: string
description: >
The VPC Subnet ID to launch in.
required: false
availability_zone:
type: string
required: false
Expand Down Expand Up @@ -101,4 +170,101 @@ node_types:
required: false
default: false

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 ID for the subnet
cidr_block:
type: string
required: true
ipv6_cidr_block :
type: string
required: false
description: The IPv6 network range for the subnet, in CIDR notation. The subnet size must use a /64 prefix length.
map_public_ip_on_launch:
type: boolean
required: false
description: Specify true to indicate that instances launched into the subnet should be assigned a public IP address.
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

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
subnets:
type: list
description: Subnetworks in this VPC
required: false
entry_schema:
type: yorc.datatypes.aws.SubnetType
security_groups:
type: list
description: SecurityGroups in this VPC
required: false
entry_schema:
type: yorc.datatypes.aws.SecurityGroupType



8 changes: 4 additions & 4 deletions deployments/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,9 @@ func GetNodePropertyValue(ctx context.Context, deploymentID, nodeName, propertyN

// GetStringNodeProperty returns the string value of a property.
// If this value is empty and the argument mandatory is true, an error is returned
func GetStringNodeProperty(ctx context.Context, deploymentID, nodeName, propertyName string, mandatory bool) (string, error) {
func GetStringNodeProperty(ctx context.Context, deploymentID, nodeName, propertyName string, mandatory bool, nestedKeys ...string) (string, error) {

result, err := GetNodePropertyValue(ctx, deploymentID, nodeName, propertyName)
result, err := GetNodePropertyValue(ctx, deploymentID, nodeName, propertyName, nestedKeys...)
if err != nil {
return "", err
}
Expand All @@ -449,9 +449,9 @@ func GetStringNodeProperty(ctx context.Context, deploymentID, nodeName, property
}

// GetBooleanNodeProperty returns the boolean value of a property (default: false)
func GetBooleanNodeProperty(ctx context.Context, deploymentID, nodeName, propertyName string) (bool, error) {
func GetBooleanNodeProperty(ctx context.Context, deploymentID, nodeName, propertyName string, nestedKeys ...string) (bool, error) {
var result bool
va, err := GetNodePropertyValue(ctx, deploymentID, nodeName, propertyName)
va, err := GetNodePropertyValue(ctx, deploymentID, nodeName, propertyName, nestedKeys...)
if err != nil {
return result, err
}
Expand Down
137 changes: 130 additions & 7 deletions prov/terraform/aws/aws_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,16 @@ func (g *awsGenerator) generateAWSInstance(ctx context.Context, cfg config.Confi
}
instance.KeyName = keyName.RawString()

// security_groups needs to contain a least one occurrence
secGroups, err := deployments.GetNodePropertyValue(ctx, deploymentID, nodeName, "security_groups")
if err != nil {
return err
}
if secGroups == nil || secGroups.RawString() == "" {
return errors.Errorf("Missing mandatory parameter 'security_groups' node type for %s", nodeName)
}

for _, secGroup := range strings.Split(strings.NewReplacer("\"", "", "'", "").Replace(secGroups.RawString()), ",") {
secGroup = strings.TrimSpace(secGroup)
instance.SecurityGroups = append(instance.SecurityGroups, secGroup)
if secGroups.RawString() != "" {
for _, secGroup := range strings.Split(strings.NewReplacer("\"", "", "'", "").Replace(secGroups.RawString()), ",") {
secGroup = strings.TrimSpace(secGroup)
instance.SecurityGroups = append(instance.SecurityGroups, secGroup)
}
}

// Get connection info (user, private key)
Expand Down Expand Up @@ -141,6 +139,131 @@ func (g *awsGenerator) generateAWSInstance(ctx context.Context, cfg config.Confi
if placementGroup != nil {
instance.PlacementGroup = placementGroup.RawString()
}

// Network
subnetID, err := deployments.GetNodePropertyValue(ctx, deploymentID, nodeName, "subnet_id")
if err != nil {
return err
}
if subnetID != nil {
instance.SubnetID = subnetID.RawString()
}

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

i := 0
for _, networkReq := range networkRequirements {
networkInterface := &NetworkInterface{}
networkInterface.SecurityGroups = make([]string, 1)

if networkReq.Relationship == "tosca.relationships.Network" {
defaultSubnetID, err := deployments.LookupInstanceAttributeValue(ctx, deploymentID, networkReq.RequirementAssignment.Node, instanceName, "default_subnet_id")
if err != nil {
return err
}
networkInterface.SubnetID = defaultSubnetID
defaultSecurityGroup, err := deployments.LookupInstanceAttributeValue(ctx, deploymentID, networkReq.RequirementAssignment.Node, instanceName, "default_security_group")
if err != nil {
return err
}
networkInterface.SecurityGroups = append(networkInterface.SecurityGroups, defaultSecurityGroup)

} else if networkReq.Relationship == "yorc.relationships.aws.Network" {
networkInterface.SubnetID, err = deployments.LookupInstanceAttributeValue(ctx, deploymentID, networkReq.RequirementAssignment.Node, instanceName, "subnet_id")
if err != nil {
return err
}
securityGroup, err := deployments.LookupInstanceAttributeValue(ctx, deploymentID, networkReq.RequirementAssignment.Node, instanceName, "subnet_id")
if err != nil {
return err
}
networkInterface.SecurityGroups = append(networkInterface.SecurityGroups, securityGroup)
}

name := strings.ToLower("network-inteface-" + strconv.Itoa(i))
name = strings.Replace(strings.ToLower(name), "_", "-", -1)

// First interface will be considered the network interface of the Compute Instance
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 as attachment to the Compute Instance
networkInterface.Attachment = map[string]string{
"instance": "${aws_instance." + instance.Tags.Name + ".id}",
"device_index": strconv.Itoa(i),
}
}

// No security groups on instance level when defining customs ENI, it will use a default one created by the VPC
instance.SecurityGroups = nil
commons.AddResource(infrastructure, "aws_network_interface", name, networkInterface)
i++
}
}

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

i := 0
for _, networkReq := range networkRequirements {
networkInterface := &NetworkInterface{}
networkInterface.SecurityGroups = make([]string, 1)

if networkReq.Relationship == "tosca.relationships.Network" {
subnetID, err := deployments.LookupInstanceAttributeValue(ctx, deploymentID, networkReq.RequirementAssignment.Node, instanceName, "subnet_id")
if err != nil {
return err
}
networkInterface.SubnetID = subnetID

networkInterface.SecurityGroups = instance.SecurityGroups

}

name := strings.ToLower("network-inteface-" + strconv.Itoa(i))
name = strings.Replace(strings.ToLower(name), "_", "-", -1)

// First interface will be considered the network interface of the Compute Instance
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 as attachment to the Compute Instance
networkInterface.Attachment = map[string]string{
"instance": "${aws_instance." + instance.Tags.Name + ".id}",
"device_index": strconv.Itoa(i),
}
}

// No security groups on instance level when defining customs ENI, it will use a default one created by the VPC
instance.SecurityGroups = nil
commons.AddResource(infrastructure, "aws_network_interface", name, networkInterface)
i++
}
}

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

Expand Down
Loading