Merge pull request #13308 from hashicorp/f-update-oracle-provider
provider/opc: Update Oracle provider
This commit is contained in:
commit
8ba93fdd8b
|
@ -1,4 +0,0 @@
|
|||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
*.go eol=lf
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,7 +1,16 @@
|
|||
## 0.9.3 (unreleased)
|
||||
|
||||
FEATURES:
|
||||
|
||||
* **New Resource:** `aws_lightsail_static_ip` [GH-13175]
|
||||
* **New Resource:** `aws_lightsail_static_ip_attachment` [GH-13207]
|
||||
* **New Resource:** `aws_ses_domain_identity` [GH-13098]
|
||||
* **New Resource:** `kubernetes_secret` [GH-12960]
|
||||
* **New Data Source:** `aws_iam_role` [GH-13213]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* backend/remote-state: Add support for assume role extensions to s3 backend [GH-13236]
|
||||
* config: New interpolation functions `basename` and `dirname`, for file path manipulation [GH-13080]
|
||||
* helper/resource: Allow unknown "pending" states [GH-13099]
|
||||
* provider/aws: Add support to set iam_role_arn on cloudformation Stack [GH-12547]
|
||||
|
@ -13,14 +22,33 @@ IMPROVEMENTS:
|
|||
* provider/aws: `aws_kinesis_firehose_delivery_stream` `password` field marked as sensitive [GH-13147]
|
||||
* provider/aws: `aws_opsworks_application` `app_source.0.password` & `ssl_configuration.0.private_key` fields marked as sensitive [GH-13147]
|
||||
* provider/aws: `aws_opsworks_stack` `custom_cookbooks_source.0.password` field marked as sensitive [GH-13147]
|
||||
* provider/aws: Support the ability to enable / disable ipv6 support in VPC [GH-12527]
|
||||
* provider/aws: Added API Gateway integration update [GH-13249]
|
||||
* provider/aws: Add `identifier` | `name_prefix` to RDS resources [GH-13232]
|
||||
* provider/aws: Validate `aws_ecs_task_definition.container_definitions` [GH-12161]
|
||||
* provider/aws: Update caller_identity data source [GH-13092]
|
||||
* provider/github: Handle the case when issue labels already exist [GH-13182]
|
||||
* provider/google: Mark `google_container_cluster`'s `client_key` & `password` inside `master_auth` as sensitive [GH-13148]
|
||||
* provider/triton: Move to joyent/triton-go [GH-13225]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: Escaped interpolation-like sequences (like `$${foo}`) now permitted in variable defaults [GH-13137]
|
||||
* provider/aws: Add Support for maintenance_window and back_window to rds_cluster_instance [GH-13134]
|
||||
* provider/aws: Increase timeout for AMI registration [GH-13159]
|
||||
* provider/aws: Increase timeouts for ELB [GH-13161]
|
||||
* provider/aws: `volume_type` of `aws_elasticsearch_domain.0.ebs_options` marked as `Computed` which prevents spurious diffs [GH-13160]
|
||||
* provider/aws: Don't set DBName on `aws_db_instance` from snapshot [GH-13140]
|
||||
* provider/aws: Add DiffSuppression to aws_ecs_service placement_strategies [GH-13220]
|
||||
* provider/aws: Refresh aws_alb_target_group stickiness on manual updates [GH-13199]
|
||||
* provider/aws: Preserve default retain_on_delete in cloudfront import [GH-13209]
|
||||
* provider/aws: Refresh aws_alb_target_group tags [GH-13200]
|
||||
* provider/aws: Set aws_vpn_connection to recreate when in deleted state [GH-13204]
|
||||
* provider/aws: Wait for aws_opsworks_instance to be running when it's specified [GH-13218]
|
||||
* provider/aws: Handle `aws_lambda_function` missing s3 key error [GH-10960]
|
||||
* provider/aws: Set stickiness to computed in alb_target_group [GH-13278]
|
||||
* provider/azurerm: Network Security Group - ignoring protocol casing at Import time [GH-13153]
|
||||
|
||||
|
||||
## 0.9.2 (March 28, 2017)
|
||||
|
||||
BACKWARDS IMCOMPATIBILITIES / NOTES:
|
||||
|
|
|
@ -21,101 +21,122 @@ import (
|
|||
func New() backend.Backend {
|
||||
s := &schema.Backend{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bucket": &schema.Schema{
|
||||
"bucket": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The name of the S3 bucket",
|
||||
},
|
||||
|
||||
"key": &schema.Schema{
|
||||
"key": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The path to the state file inside the bucket",
|
||||
},
|
||||
|
||||
"region": &schema.Schema{
|
||||
"region": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The region of the S3 bucket.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("AWS_DEFAULT_REGION", nil),
|
||||
},
|
||||
|
||||
"endpoint": &schema.Schema{
|
||||
"endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "A custom endpoint for the S3 API",
|
||||
DefaultFunc: schema.EnvDefaultFunc("AWS_S3_ENDPOINT", ""),
|
||||
},
|
||||
|
||||
"encrypt": &schema.Schema{
|
||||
"encrypt": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Description: "Whether to enable server side encryption of the state file",
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"acl": &schema.Schema{
|
||||
"acl": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "Canned ACL to be applied to the state file",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"access_key": &schema.Schema{
|
||||
"access_key": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "AWS access key",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"secret_key": &schema.Schema{
|
||||
"secret_key": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "AWS secret key",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"kms_key_id": &schema.Schema{
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The ARN of a KMS Key to use for encrypting the state",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"lock_table": &schema.Schema{
|
||||
"lock_table": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "DynamoDB table for state locking",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"profile": &schema.Schema{
|
||||
"profile": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "AWS profile name",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"shared_credentials_file": &schema.Schema{
|
||||
"shared_credentials_file": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "Path to a shared credentials file",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"token": &schema.Schema{
|
||||
"token": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "MFA token",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"role_arn": &schema.Schema{
|
||||
"role_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The role to be assumed",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"session_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The session name to use when assuming the role.",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"external_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The external ID to use when assuming the role",
|
||||
Default: "",
|
||||
},
|
||||
|
||||
"assume_role_policy": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "The permissions applied when assuming a role.",
|
||||
Default: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -162,6 +183,9 @@ func (b *Backend) configure(ctx context.Context) error {
|
|||
Profile: data.Get("profile").(string),
|
||||
CredsFilename: data.Get("shared_credentials_file").(string),
|
||||
AssumeRoleARN: data.Get("role_arn").(string),
|
||||
AssumeRoleSessionName: data.Get("session_name").(string),
|
||||
AssumeRoleExternalID: data.Get("external_id").(string),
|
||||
AssumeRolePolicy: data.Get("assume_role_policy").(string),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/builtin/providers/opc"
|
||||
"github.com/hashicorp/terraform/plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Serve(&plugin.ServeOpts{
|
||||
ProviderFunc: opc.Provider,
|
||||
})
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
|
@ -17,24 +18,40 @@ func dataSourceAwsCallerIdentity() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"user_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*AWSClient)
|
||||
client := meta.(*AWSClient).stsconn
|
||||
|
||||
res, err := client.GetCallerIdentity(&sts.GetCallerIdentityInput{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting Caller Identity: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Reading Caller Identity.")
|
||||
d.SetId(time.Now().UTC().String())
|
||||
|
||||
if client.accountid == "" {
|
||||
if *res.Account == "" {
|
||||
log.Println("[DEBUG] No Account ID available, failing")
|
||||
return fmt.Errorf("No AWS Account ID is available to the provider. Please ensure that\n" +
|
||||
"skip_requesting_account_id is not set on the AWS provider.")
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Setting AWS Account ID to %s.", client.accountid)
|
||||
d.Set("account_id", meta.(*AWSClient).accountid)
|
||||
|
||||
log.Printf("[DEBUG] Setting AWS Account ID to %s.", *res.Account)
|
||||
d.Set("account_id", res.Account)
|
||||
d.Set("arn", res.Arn)
|
||||
d.Set("user_id", res.UserId)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -39,6 +39,14 @@ func testAccCheckAwsCallerIdentityAccountId(n string) resource.TestCheckFunc {
|
|||
return fmt.Errorf("Incorrect Account ID: expected %q, got %q", expected, rs.Primary.Attributes["account_id"])
|
||||
}
|
||||
|
||||
if rs.Primary.Attributes["user_id"] == "" {
|
||||
return fmt.Errorf("UserID expected to not be nil")
|
||||
}
|
||||
|
||||
if rs.Primary.Attributes["arn"] == "" {
|
||||
return fmt.Errorf("ARN expected to not be nil")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceAwsIAMRole() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceAwsIAMRoleRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"assume_role_policy_document": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"path": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"role_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"role_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceAwsIAMRoleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
roleName := d.Get("role_name").(string)
|
||||
|
||||
req := &iam.GetRoleInput{
|
||||
RoleName: aws.String(roleName),
|
||||
}
|
||||
|
||||
resp, err := iamconn.GetRole(req)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error getting roles: {{err}}", err)
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("no IAM role found")
|
||||
}
|
||||
|
||||
role := resp.Role
|
||||
|
||||
d.SetId(*role.RoleId)
|
||||
d.Set("arn", role.Arn)
|
||||
d.Set("assume_role_policy_document", role.AssumeRolePolicyDocument)
|
||||
d.Set("path", role.Path)
|
||||
d.Set("role_id", role.RoleId)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccAWSDataSourceIAMRole_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsIAMRoleConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttrSet("data.aws_iam_role.test", "role_id"),
|
||||
resource.TestCheckResourceAttr("data.aws_iam_role.test", "assume_role_policy_document", "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D"),
|
||||
resource.TestCheckResourceAttr("data.aws_iam_role.test", "path", "/testpath/"),
|
||||
resource.TestCheckResourceAttr("data.aws_iam_role.test", "role_name", "TestRole"),
|
||||
resource.TestMatchResourceAttr("data.aws_iam_role.test", "arn", regexp.MustCompile("^arn:aws:iam::[0-9]{12}:role/testpath/TestRole$")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const testAccAwsIAMRoleConfig = `
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "test_role" {
|
||||
name = "TestRole"
|
||||
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "ec2.amazonaws.com"
|
||||
},
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
path = "/testpath/"
|
||||
}
|
||||
|
||||
data "aws_iam_role" "test" {
|
||||
role_name = "${aws_iam_role.test_role.name}"
|
||||
}
|
||||
`
|
|
@ -136,7 +136,7 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro
|
|||
|
||||
if matchingTags && matchingVPC {
|
||||
if hostedZoneFound != nil {
|
||||
return fmt.Errorf("multplie Route53Zone found please use vpc_id option to filter")
|
||||
return fmt.Errorf("multiple Route53Zone found please use vpc_id option to filter")
|
||||
} else {
|
||||
hostedZoneFound = hostedZone
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ import (
|
|||
)
|
||||
|
||||
func resourceAwsCloudFrontDistributionImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
// This is a non API attribute
|
||||
// We are merely setting this to the same value as the Default setting in the schema
|
||||
d.Set("retain_on_delete", false)
|
||||
|
||||
conn := meta.(*AWSClient).cloudfrontconn
|
||||
id := d.Id()
|
||||
resp, err := conn.GetDistributionConfig(&cloudfront.GetDistributionConfigInput{
|
||||
|
|
|
@ -19,16 +19,13 @@ func TestAccAWSCloudFrontDistribution_importBasic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckCloudFrontDistributionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testConfig,
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
// Ignore retain_on_delete since it doesn't come from the AWS
|
||||
// API.
|
||||
ImportStateVerifyIgnore: []string{"retain_on_delete"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -174,6 +174,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
|
||||
"aws_iam_account_alias": dataSourceAwsIamAccountAlias(),
|
||||
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
|
||||
"aws_iam_role": dataSourceAwsIAMRole(),
|
||||
"aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(),
|
||||
"aws_instance": dataSourceAwsInstance(),
|
||||
"aws_ip_ranges": dataSourceAwsIPRanges(),
|
||||
|
@ -337,6 +338,8 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_lightsail_domain": resourceAwsLightsailDomain(),
|
||||
"aws_lightsail_instance": resourceAwsLightsailInstance(),
|
||||
"aws_lightsail_key_pair": resourceAwsLightsailKeyPair(),
|
||||
"aws_lightsail_static_ip": resourceAwsLightsailStaticIp(),
|
||||
"aws_lightsail_static_ip_attachment": resourceAwsLightsailStaticIpAttachment(),
|
||||
"aws_lb_cookie_stickiness_policy": resourceAwsLBCookieStickinessPolicy(),
|
||||
"aws_load_balancer_policy": resourceAwsLoadBalancerPolicy(),
|
||||
"aws_load_balancer_backend_server_policy": resourceAwsLoadBalancerBackendServerPolicies(),
|
||||
|
@ -383,6 +386,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_route_table": resourceAwsRouteTable(),
|
||||
"aws_route_table_association": resourceAwsRouteTableAssociation(),
|
||||
"aws_ses_active_receipt_rule_set": resourceAwsSesActiveReceiptRuleSet(),
|
||||
"aws_ses_domain_identity": resourceAwsSesDomainIdentity(),
|
||||
"aws_ses_receipt_filter": resourceAwsSesReceiptFilter(),
|
||||
"aws_ses_receipt_rule": resourceAwsSesReceiptRule(),
|
||||
"aws_ses_receipt_rule_set": resourceAwsSesReceiptRuleSet(),
|
||||
|
|
|
@ -73,6 +73,7 @@ func resourceAwsAlbTargetGroup() *schema.Resource {
|
|||
"stickiness": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
|
@ -258,11 +259,19 @@ func resourceAwsAlbTargetGroupRead(d *schema.ResourceData, meta interface{}) err
|
|||
for _, attr := range attrResp.Attributes {
|
||||
switch *attr.Key {
|
||||
case "stickiness.enabled":
|
||||
stickinessMap["enabled"] = *attr.Value
|
||||
enabled, err := strconv.ParseBool(*attr.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error converting stickiness.enabled to bool: %s", *attr.Value)
|
||||
}
|
||||
stickinessMap["enabled"] = enabled
|
||||
case "stickiness.type":
|
||||
stickinessMap["type"] = *attr.Value
|
||||
case "stickiness.lb_cookie.duration_seconds":
|
||||
stickinessMap["cookie_duration"] = *attr.Value
|
||||
duration, err := strconv.Atoi(*attr.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error converting stickiness.lb_cookie.duration_seconds to int: %s", *attr.Value)
|
||||
}
|
||||
stickinessMap["cookie_duration"] = duration
|
||||
case "deregistration_delay.timeout_seconds":
|
||||
timeout, err := strconv.Atoi(*attr.Value)
|
||||
if err != nil {
|
||||
|
@ -271,7 +280,24 @@ func resourceAwsAlbTargetGroupRead(d *schema.ResourceData, meta interface{}) err
|
|||
d.Set("deregistration_delay", timeout)
|
||||
}
|
||||
}
|
||||
d.Set("stickiness", []interface{}{stickinessMap})
|
||||
|
||||
if err := d.Set("stickiness", []interface{}{stickinessMap}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tagsResp, err := elbconn.DescribeTags(&elbv2.DescribeTagsInput{
|
||||
ResourceArns: []*string{aws.String(d.Id())},
|
||||
})
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error retrieving Target Group Tags: {{err}}", err)
|
||||
}
|
||||
for _, t := range tagsResp.TagDescriptions {
|
||||
if *t.ResourceArn == d.Id() {
|
||||
if err := d.Set("tags", tagsToMapELBv2(t.Tags)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -77,6 +77,8 @@ func TestAccAWSALBTargetGroup_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("aws_alb_target_group.test", "health_check.0.healthy_threshold", "3"),
|
||||
resource.TestCheckResourceAttr("aws_alb_target_group.test", "health_check.0.unhealthy_threshold", "3"),
|
||||
resource.TestCheckResourceAttr("aws_alb_target_group.test", "health_check.0.matcher", "200-299"),
|
||||
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.%", "1"),
|
||||
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.TestName", "TestAccAWSALBTargetGroup_basic"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
AWSAMIRetryTimeout = 10 * time.Minute
|
||||
AWSAMIRetryTimeout = 20 * time.Minute
|
||||
AWSAMIDeleteRetryTimeout = 20 * time.Minute
|
||||
AWSAMIRetryDelay = 5 * time.Second
|
||||
AWSAMIRetryMinTimeout = 3 * time.Second
|
||||
|
|
|
@ -11,87 +11,94 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/apigateway"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func resourceAwsApiGatewayIntegration() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsApiGatewayIntegrationCreate,
|
||||
Read: resourceAwsApiGatewayIntegrationRead,
|
||||
Update: resourceAwsApiGatewayIntegrationCreate,
|
||||
Update: resourceAwsApiGatewayIntegrationUpdate,
|
||||
Delete: resourceAwsApiGatewayIntegrationDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"rest_api_id": &schema.Schema{
|
||||
"rest_api_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"resource_id": &schema.Schema{
|
||||
"resource_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"http_method": &schema.Schema{
|
||||
"http_method": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateHTTPMethod,
|
||||
},
|
||||
|
||||
"type": &schema.Schema{
|
||||
"type": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateApiGatewayIntegrationType,
|
||||
},
|
||||
|
||||
"uri": &schema.Schema{
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"credentials": &schema.Schema{
|
||||
"credentials": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"integration_http_method": &schema.Schema{
|
||||
"integration_http_method": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateHTTPMethod,
|
||||
},
|
||||
|
||||
"request_templates": &schema.Schema{
|
||||
"request_templates": {
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Elem: schema.TypeString,
|
||||
},
|
||||
|
||||
"request_parameters": &schema.Schema{
|
||||
"request_parameters": {
|
||||
Type: schema.TypeMap,
|
||||
Elem: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"request_parameters_in_json"},
|
||||
},
|
||||
|
||||
"request_parameters_in_json": &schema.Schema{
|
||||
"request_parameters_in_json": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"request_parameters"},
|
||||
Deprecated: "Use field request_parameters instead",
|
||||
},
|
||||
|
||||
"content_handling": &schema.Schema{
|
||||
"content_handling": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateApiGatewayIntegrationContentHandling,
|
||||
},
|
||||
|
||||
"passthrough_behavior": &schema.Schema{
|
||||
"passthrough_behavior": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateApiGatewayIntegrationPassthroughBehavior,
|
||||
},
|
||||
},
|
||||
|
@ -101,6 +108,7 @@ func resourceAwsApiGatewayIntegration() *schema.Resource {
|
|||
func resourceAwsApiGatewayIntegrationCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).apigateway
|
||||
|
||||
log.Print("[DEBUG] Creating API Gateway Integration")
|
||||
var integrationHttpMethod *string
|
||||
if v, ok := d.GetOk("integration_http_method"); ok {
|
||||
integrationHttpMethod = aws.String(v.(string))
|
||||
|
@ -163,13 +171,13 @@ func resourceAwsApiGatewayIntegrationCreate(d *schema.ResourceData, meta interfa
|
|||
|
||||
d.SetId(fmt.Sprintf("agi-%s-%s-%s", d.Get("rest_api_id").(string), d.Get("resource_id").(string), d.Get("http_method").(string)))
|
||||
|
||||
return nil
|
||||
return resourceAwsApiGatewayIntegrationRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsApiGatewayIntegrationRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).apigateway
|
||||
|
||||
log.Printf("[DEBUG] Reading API Gateway Integration %s", d.Id())
|
||||
log.Printf("[DEBUG] Reading API Gateway Integration: %s", d.Id())
|
||||
integration, err := conn.GetIntegration(&apigateway.GetIntegrationInput{
|
||||
HttpMethod: aws.String(d.Get("http_method").(string)),
|
||||
ResourceId: aws.String(d.Get("resource_id").(string)),
|
||||
|
@ -191,17 +199,127 @@ func resourceAwsApiGatewayIntegrationRead(d *schema.ResourceData, meta interface
|
|||
}
|
||||
|
||||
d.Set("request_templates", aws.StringValueMap(integration.RequestTemplates))
|
||||
d.Set("credentials", integration.Credentials)
|
||||
d.Set("type", integration.Type)
|
||||
d.Set("uri", integration.Uri)
|
||||
d.Set("request_parameters", aws.StringValueMap(integration.RequestParameters))
|
||||
d.Set("request_parameters_in_json", aws.StringValueMap(integration.RequestParameters))
|
||||
d.Set("passthrough_behavior", integration.PassthroughBehavior)
|
||||
|
||||
if integration.Uri != nil {
|
||||
d.Set("uri", integration.Uri)
|
||||
}
|
||||
|
||||
if integration.Credentials != nil {
|
||||
d.Set("credentials", integration.Credentials)
|
||||
}
|
||||
|
||||
if integration.ContentHandling != nil {
|
||||
d.Set("content_handling", integration.ContentHandling)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsApiGatewayIntegrationUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).apigateway
|
||||
|
||||
log.Printf("[DEBUG] Updating API Gateway Integration: %s", d.Id())
|
||||
operations := make([]*apigateway.PatchOperation, 0)
|
||||
|
||||
// https://docs.aws.amazon.com/apigateway/api-reference/link-relation/integration-update/#remarks
|
||||
// According to the above documentation, only a few parts are addable / removable.
|
||||
if d.HasChange("request_templates") {
|
||||
o, n := d.GetChange("request_templates")
|
||||
prefix := "requestTemplates"
|
||||
|
||||
os := o.(map[string]interface{})
|
||||
ns := n.(map[string]interface{})
|
||||
|
||||
// Handle Removal
|
||||
for k := range os {
|
||||
if _, ok := ns[k]; !ok {
|
||||
operations = append(operations, &apigateway.PatchOperation{
|
||||
Op: aws.String("remove"),
|
||||
Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range ns {
|
||||
// Handle replaces
|
||||
if _, ok := os[k]; ok {
|
||||
operations = append(operations, &apigateway.PatchOperation{
|
||||
Op: aws.String("replace"),
|
||||
Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
|
||||
Value: aws.String(v.(string)),
|
||||
})
|
||||
}
|
||||
|
||||
// Handle additions
|
||||
if _, ok := os[k]; !ok {
|
||||
operations = append(operations, &apigateway.PatchOperation{
|
||||
Op: aws.String("add"),
|
||||
Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
|
||||
Value: aws.String(v.(string)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("request_parameters") {
|
||||
o, n := d.GetChange("request_parameters")
|
||||
prefix := "requestParameters"
|
||||
|
||||
os := o.(map[string]interface{})
|
||||
ns := n.(map[string]interface{})
|
||||
|
||||
// Handle Removal
|
||||
for k := range os {
|
||||
if _, ok := ns[k]; !ok {
|
||||
operations = append(operations, &apigateway.PatchOperation{
|
||||
Op: aws.String("remove"),
|
||||
Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range ns {
|
||||
// Handle replaces
|
||||
if _, ok := os[k]; ok {
|
||||
operations = append(operations, &apigateway.PatchOperation{
|
||||
Op: aws.String("replace"),
|
||||
Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
|
||||
Value: aws.String(v.(string)),
|
||||
})
|
||||
}
|
||||
|
||||
// Handle additions
|
||||
if _, ok := os[k]; !ok {
|
||||
operations = append(operations, &apigateway.PatchOperation{
|
||||
Op: aws.String("add"),
|
||||
Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
|
||||
Value: aws.String(v.(string)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params := &apigateway.UpdateIntegrationInput{
|
||||
HttpMethod: aws.String(d.Get("http_method").(string)),
|
||||
ResourceId: aws.String(d.Get("resource_id").(string)),
|
||||
RestApiId: aws.String(d.Get("rest_api_id").(string)),
|
||||
PatchOperations: operations,
|
||||
}
|
||||
|
||||
_, err := conn.UpdateIntegration(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating API Gateway Integration: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("agi-%s-%s-%s", d.Get("rest_api_id").(string), d.Get("resource_id").(string), d.Get("http_method").(string)))
|
||||
|
||||
return resourceAwsApiGatewayIntegrationRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsApiGatewayIntegrationDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).apigateway
|
||||
log.Printf("[DEBUG] Deleting API Gateway Integration: %s", d.Id())
|
||||
|
|
|
@ -19,88 +19,80 @@ func TestAccAWSAPIGatewayIntegration_basic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSAPIGatewayIntegrationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSAPIGatewayIntegrationConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSAPIGatewayIntegrationExists("aws_api_gateway_integration.test", &conf),
|
||||
testAccCheckAWSAPIGatewayIntegrationAttributes(&conf),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "type", "HTTP"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "integration_http_method", "GET"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "uri", "https://www.google.de"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "request_templates.application/json", ""),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "request_templates.application/xml", "#set($inputRoot = $input.path('$'))\n{ }"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "passthrough_behavior", "WHEN_NO_MATCH"),
|
||||
resource.TestCheckNoResourceAttr(
|
||||
"aws_api_gateway_integration.test", "content_handling"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "type", "HTTP"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "integration_http_method", "GET"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "uri", "https://www.google.de"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "passthrough_behavior", "WHEN_NO_MATCH"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "content_handling", "CONVERT_TO_TEXT"),
|
||||
resource.TestCheckNoResourceAttr("aws_api_gateway_integration.test", "credentials"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.%", "2"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.integration.request.header.X-Authorization", "'static'"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.integration.request.header.X-Foo", "'Bar'"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.%", "2"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.application/json", ""),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.application/xml", "#set($inputRoot = $input.path('$'))\n{ }"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSAPIGatewayIntegrationConfigUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSAPIGatewayIntegrationExists("aws_api_gateway_integration.test", &conf),
|
||||
testAccCheckAWSAPIGatewayMockIntegrationAttributes(&conf),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "type", "MOCK"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "integration_http_method", ""),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "uri", ""),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "passthrough_behavior", "NEVER"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_api_gateway_integration.test", "content_handling", "CONVERT_TO_BINARY"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "type", "HTTP"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "integration_http_method", "GET"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "uri", "https://www.google.de"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "passthrough_behavior", "WHEN_NO_MATCH"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "content_handling", "CONVERT_TO_TEXT"),
|
||||
resource.TestCheckNoResourceAttr("aws_api_gateway_integration.test", "credentials"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.%", "2"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.integration.request.header.X-Authorization", "'updated'"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.integration.request.header.X-FooBar", "'Baz'"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.%", "2"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.application/json", "{'foobar': 'bar}"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.text/html", "<html>Foo</html>"),
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
Config: testAccAWSAPIGatewayIntegrationConfigUpdateNoTemplates,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSAPIGatewayIntegrationExists("aws_api_gateway_integration.test", &conf),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "type", "HTTP"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "integration_http_method", "GET"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "uri", "https://www.google.de"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "passthrough_behavior", "WHEN_NO_MATCH"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "content_handling", "CONVERT_TO_TEXT"),
|
||||
resource.TestCheckNoResourceAttr("aws_api_gateway_integration.test", "credentials"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.%", "0"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.%", "0"),
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
Config: testAccAWSAPIGatewayIntegrationConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSAPIGatewayIntegrationExists("aws_api_gateway_integration.test", &conf),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "type", "HTTP"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "integration_http_method", "GET"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "uri", "https://www.google.de"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "passthrough_behavior", "WHEN_NO_MATCH"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "content_handling", "CONVERT_TO_TEXT"),
|
||||
resource.TestCheckNoResourceAttr("aws_api_gateway_integration.test", "credentials"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.%", "2"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_parameters.integration.request.header.X-Authorization", "'static'"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.%", "2"),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.application/json", ""),
|
||||
resource.TestCheckResourceAttr("aws_api_gateway_integration.test", "request_templates.application/xml", "#set($inputRoot = $input.path('$'))\n{ }"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAWSAPIGatewayMockIntegrationAttributes(conf *apigateway.Integration) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if *conf.Type != "MOCK" {
|
||||
return fmt.Errorf("Wrong Type: %q", *conf.Type)
|
||||
}
|
||||
if *conf.RequestParameters["integration.request.header.X-Authorization"] != "'updated'" {
|
||||
return fmt.Errorf("wrong updated RequestParameters for header.X-Authorization")
|
||||
}
|
||||
if *conf.ContentHandling != "CONVERT_TO_BINARY" {
|
||||
return fmt.Errorf("wrong ContentHandling: %q", *conf.ContentHandling)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSAPIGatewayIntegrationAttributes(conf *apigateway.Integration) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if *conf.HttpMethod == "" {
|
||||
return fmt.Errorf("empty HttpMethod")
|
||||
}
|
||||
if *conf.Uri != "https://www.google.de" {
|
||||
return fmt.Errorf("wrong Uri")
|
||||
}
|
||||
if *conf.Type != "HTTP" {
|
||||
return fmt.Errorf("wrong Type")
|
||||
}
|
||||
if conf.RequestTemplates["application/json"] != nil {
|
||||
return fmt.Errorf("wrong RequestTemplate for application/json")
|
||||
}
|
||||
if *conf.RequestTemplates["application/xml"] != "#set($inputRoot = $input.path('$'))\n{ }" {
|
||||
return fmt.Errorf("wrong RequestTemplate for application/xml")
|
||||
}
|
||||
if *conf.RequestParameters["integration.request.header.X-Authorization"] != "'static'" {
|
||||
return fmt.Errorf("wrong RequestParameters for header.X-Authorization")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSAPIGatewayIntegrationExists(n string, res *apigateway.Integration) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
@ -197,12 +189,14 @@ resource "aws_api_gateway_integration" "test" {
|
|||
|
||||
request_parameters = {
|
||||
"integration.request.header.X-Authorization" = "'static'"
|
||||
"integration.request.header.X-Foo" = "'Bar'"
|
||||
}
|
||||
|
||||
type = "HTTP"
|
||||
uri = "https://www.google.de"
|
||||
integration_http_method = "GET"
|
||||
passthrough_behavior = "WHEN_NO_MATCH"
|
||||
content_handling = "CONVERT_TO_TEXT"
|
||||
}
|
||||
`
|
||||
|
||||
|
@ -233,13 +227,55 @@ resource "aws_api_gateway_integration" "test" {
|
|||
resource_id = "${aws_api_gateway_resource.test.id}"
|
||||
http_method = "${aws_api_gateway_method.test.http_method}"
|
||||
|
||||
request_parameters = {
|
||||
"integration.request.header.X-Authorization" = "'updated'"
|
||||
request_templates = {
|
||||
"application/json" = "{'foobar': 'bar}"
|
||||
"text/html" = "<html>Foo</html>"
|
||||
}
|
||||
|
||||
type = "MOCK"
|
||||
passthrough_behavior = "NEVER"
|
||||
content_handling = "CONVERT_TO_BINARY"
|
||||
request_parameters = {
|
||||
"integration.request.header.X-Authorization" = "'updated'"
|
||||
"integration.request.header.X-FooBar" = "'Baz'"
|
||||
}
|
||||
|
||||
type = "HTTP"
|
||||
uri = "https://www.google.de"
|
||||
integration_http_method = "GET"
|
||||
passthrough_behavior = "WHEN_NO_MATCH"
|
||||
content_handling = "CONVERT_TO_TEXT"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAWSAPIGatewayIntegrationConfigUpdateNoTemplates = `
|
||||
resource "aws_api_gateway_rest_api" "test" {
|
||||
name = "test"
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_resource" "test" {
|
||||
rest_api_id = "${aws_api_gateway_rest_api.test.id}"
|
||||
parent_id = "${aws_api_gateway_rest_api.test.root_resource_id}"
|
||||
path_part = "test"
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_method" "test" {
|
||||
rest_api_id = "${aws_api_gateway_rest_api.test.id}"
|
||||
resource_id = "${aws_api_gateway_resource.test.id}"
|
||||
http_method = "GET"
|
||||
authorization = "NONE"
|
||||
|
||||
request_models = {
|
||||
"application/json" = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_integration" "test" {
|
||||
rest_api_id = "${aws_api_gateway_rest_api.test.id}"
|
||||
resource_id = "${aws_api_gateway_resource.test.id}"
|
||||
http_method = "${aws_api_gateway_method.test.http_method}"
|
||||
|
||||
type = "HTTP"
|
||||
uri = "https://www.google.de"
|
||||
integration_http_method = "GET"
|
||||
passthrough_behavior = "WHEN_NO_MATCH"
|
||||
content_handling = "CONVERT_TO_TEXT"
|
||||
}
|
||||
`
|
||||
|
|
|
@ -105,7 +105,15 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsId,
|
||||
ConflictsWith: []string{"identifier_prefix"},
|
||||
ValidateFunc: validateRdsIdentifier,
|
||||
},
|
||||
"identifier_prefix": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsIdentifierPrefix,
|
||||
},
|
||||
|
||||
"instance_class": {
|
||||
|
@ -336,10 +344,16 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
|
|||
conn := meta.(*AWSClient).rdsconn
|
||||
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
|
||||
|
||||
identifier := d.Get("identifier").(string)
|
||||
// Generate a unique ID for the user
|
||||
if identifier == "" {
|
||||
identifier = resource.PrefixedUniqueId("tf-")
|
||||
var identifier string
|
||||
if v, ok := d.GetOk("identifier"); ok {
|
||||
identifier = v.(string)
|
||||
} else {
|
||||
if v, ok := d.GetOk("identifier_prefix"); ok {
|
||||
identifier = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
identifier = resource.UniqueId()
|
||||
}
|
||||
|
||||
// SQL Server identifier size is max 15 chars, so truncate
|
||||
if engine := d.Get("engine").(string); engine != "" {
|
||||
if strings.Contains(strings.ToLower(engine), "sqlserver") {
|
||||
|
@ -407,8 +421,15 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
|
||||
if attr, ok := d.GetOk("name"); ok {
|
||||
// "Note: This parameter [DBName] doesn't apply to the MySQL, PostgreSQL, or MariaDB engines."
|
||||
// https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html
|
||||
switch strings.ToLower(d.Get("engine").(string)) {
|
||||
case "mysql", "postgres", "mariadb":
|
||||
// skip
|
||||
default:
|
||||
opts.DBName = aws.String(attr.(string))
|
||||
}
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("availability_zone"); ok {
|
||||
opts.AvailabilityZone = aws.String(attr.(string))
|
||||
|
|
|
@ -53,6 +53,46 @@ func TestAccAWSDBInstance_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBInstance_namePrefix(t *testing.T) {
|
||||
var v rds.DBInstance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSDBInstanceConfig_namePrefix,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBInstanceExists("aws_db_instance.test", &v),
|
||||
testAccCheckAWSDBInstanceAttributes(&v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_db_instance.test", "identifier", regexp.MustCompile("^tf-test-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBInstance_generatedName(t *testing.T) {
|
||||
var v rds.DBInstance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSDBInstanceConfig_generatedName,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBInstanceExists("aws_db_instance.test", &v),
|
||||
testAccCheckAWSDBInstanceAttributes(&v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBInstance_kmsKey(t *testing.T) {
|
||||
var v rds.DBInstance
|
||||
keyRegex := regexp.MustCompile("^arn:aws:kms:")
|
||||
|
@ -628,6 +668,37 @@ resource "aws_db_instance" "bar" {
|
|||
}
|
||||
}`
|
||||
|
||||
const testAccAWSDBInstanceConfig_namePrefix = `
|
||||
resource "aws_db_instance" "test" {
|
||||
allocated_storage = 10
|
||||
engine = "MySQL"
|
||||
identifier_prefix = "tf-test-"
|
||||
instance_class = "db.t1.micro"
|
||||
password = "password"
|
||||
username = "root"
|
||||
publicly_accessible = true
|
||||
skip_final_snapshot = true
|
||||
|
||||
timeouts {
|
||||
create = "30m"
|
||||
}
|
||||
}`
|
||||
|
||||
const testAccAWSDBInstanceConfig_generatedName = `
|
||||
resource "aws_db_instance" "test" {
|
||||
allocated_storage = 10
|
||||
engine = "MySQL"
|
||||
instance_class = "db.t1.micro"
|
||||
password = "password"
|
||||
username = "root"
|
||||
publicly_accessible = true
|
||||
skip_final_snapshot = true
|
||||
|
||||
timeouts {
|
||||
create = "30m"
|
||||
}
|
||||
}`
|
||||
|
||||
var testAccAWSDBInstanceConfigKmsKeyId = `
|
||||
resource "aws_kms_key" "foo" {
|
||||
description = "Terraform acc test %s"
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
@ -32,10 +31,19 @@ func resourceAwsDbOptionGroup() *schema.Resource {
|
|||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
ConflictsWith: []string{"name_prefix"},
|
||||
ValidateFunc: validateDbOptionGroupName,
|
||||
},
|
||||
"name_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateDbOptionGroupNamePrefix,
|
||||
},
|
||||
"engine_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
|
@ -48,8 +56,9 @@ func resourceAwsDbOptionGroup() *schema.Resource {
|
|||
},
|
||||
"option_group_description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: "Managed by Terraform",
|
||||
},
|
||||
|
||||
"option": &schema.Schema{
|
||||
|
@ -107,11 +116,20 @@ func resourceAwsDbOptionGroupCreate(d *schema.ResourceData, meta interface{}) er
|
|||
rdsconn := meta.(*AWSClient).rdsconn
|
||||
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
|
||||
|
||||
var groupName string
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
groupName = v.(string)
|
||||
} else if v, ok := d.GetOk("name_prefix"); ok {
|
||||
groupName = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
groupName = resource.UniqueId()
|
||||
}
|
||||
|
||||
createOpts := &rds.CreateOptionGroupInput{
|
||||
EngineName: aws.String(d.Get("engine_name").(string)),
|
||||
MajorEngineVersion: aws.String(d.Get("major_engine_version").(string)),
|
||||
OptionGroupDescription: aws.String(d.Get("option_group_description").(string)),
|
||||
OptionGroupName: aws.String(d.Get("name").(string)),
|
||||
OptionGroupName: aws.String(groupName),
|
||||
Tags: tags,
|
||||
}
|
||||
|
||||
|
@ -121,7 +139,7 @@ func resourceAwsDbOptionGroupCreate(d *schema.ResourceData, meta interface{}) er
|
|||
return fmt.Errorf("Error creating DB Option Group: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(d.Get("name").(string))
|
||||
d.SetId(groupName)
|
||||
log.Printf("[INFO] DB Option Group ID: %s", d.Id())
|
||||
|
||||
return resourceAwsDbOptionGroupUpdate(d, meta)
|
||||
|
@ -343,28 +361,3 @@ func buildRDSOptionGroupARN(identifier, partition, accountid, region string) (st
|
|||
arn := fmt.Sprintf("arn:%s:rds:%s:%s:og:%s", partition, region, accountid, identifier)
|
||||
return arn, nil
|
||||
}
|
||||
|
||||
func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"first character of %q must be a letter", k))
|
||||
}
|
||||
if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only alphanumeric characters and hyphens allowed in %q", k))
|
||||
}
|
||||
if regexp.MustCompile(`--`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot contain two consecutive hyphens", k))
|
||||
}
|
||||
if regexp.MustCompile(`-$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot end with a hyphen", k))
|
||||
}
|
||||
if len(value) > 255 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be greater than 255 characters", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package aws
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
@ -34,6 +35,66 @@ func TestAccAWSDBOptionGroup_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBOptionGroup_namePrefix(t *testing.T) {
|
||||
var v rds.OptionGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBOptionGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSDBOptionGroup_namePrefix,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBOptionGroupExists("aws_db_option_group.test", &v),
|
||||
testAccCheckAWSDBOptionGroupAttributes(&v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_db_option_group.test", "name", regexp.MustCompile("^tf-test-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBOptionGroup_generatedName(t *testing.T) {
|
||||
var v rds.OptionGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBOptionGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSDBOptionGroup_generatedName,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBOptionGroupExists("aws_db_option_group.test", &v),
|
||||
testAccCheckAWSDBOptionGroupAttributes(&v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBOptionGroup_defaultDescription(t *testing.T) {
|
||||
var v rds.OptionGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBOptionGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSDBOptionGroup_defaultDescription(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBOptionGroupExists("aws_db_option_group.test", &v),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_option_group.test", "option_group_description", "Managed by Terraform"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBOptionGroup_basicDestroyWithInstance(t *testing.T) {
|
||||
rName := fmt.Sprintf("option-group-test-terraform-%s", acctest.RandString(5))
|
||||
|
||||
|
@ -160,42 +221,6 @@ func testAccCheckAWSDBOptionGroupAttributes(v *rds.OptionGroup) resource.TestChe
|
|||
}
|
||||
}
|
||||
|
||||
func TestResourceAWSDBOptionGroupName_validation(t *testing.T) {
|
||||
cases := []struct {
|
||||
Value string
|
||||
ErrCount int
|
||||
}{
|
||||
{
|
||||
Value: "testing123!",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "1testing123",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing--123",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing123-",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: randomString(256),
|
||||
ErrCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, errors := validateDbOptionGroupName(tc.Value, "aws_db_option_group_name")
|
||||
|
||||
if len(errors) != tc.ErrCount {
|
||||
t.Fatalf("Expected the DB Option Group Name to trigger a validation error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSDBOptionGroupExists(n string, v *rds.OptionGroup) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
@ -387,3 +412,30 @@ resource "aws_db_option_group" "bar" {
|
|||
}
|
||||
`, r)
|
||||
}
|
||||
|
||||
const testAccAWSDBOptionGroup_namePrefix = `
|
||||
resource "aws_db_option_group" "test" {
|
||||
name_prefix = "tf-test-"
|
||||
option_group_description = "Test option group for terraform"
|
||||
engine_name = "mysql"
|
||||
major_engine_version = "5.6"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAWSDBOptionGroup_generatedName = `
|
||||
resource "aws_db_option_group" "test" {
|
||||
option_group_description = "Test option group for terraform"
|
||||
engine_name = "mysql"
|
||||
major_engine_version = "5.6"
|
||||
}
|
||||
`
|
||||
|
||||
func testAccAWSDBOptionGroup_defaultDescription(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_db_option_group" "test" {
|
||||
name = "tf-test-%d"
|
||||
engine_name = "mysql"
|
||||
major_engine_version = "5.6"
|
||||
}
|
||||
`, n)
|
||||
}
|
||||
|
|
|
@ -33,10 +33,19 @@ func resourceAwsDbParameterGroup() *schema.Resource {
|
|||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
ConflictsWith: []string{"name_prefix"},
|
||||
ValidateFunc: validateDbParamGroupName,
|
||||
},
|
||||
"name_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateDbParamGroupNamePrefix,
|
||||
},
|
||||
"family": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
|
@ -81,8 +90,17 @@ func resourceAwsDbParameterGroupCreate(d *schema.ResourceData, meta interface{})
|
|||
rdsconn := meta.(*AWSClient).rdsconn
|
||||
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
|
||||
|
||||
var groupName string
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
groupName = v.(string)
|
||||
} else if v, ok := d.GetOk("name_prefix"); ok {
|
||||
groupName = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
groupName = resource.UniqueId()
|
||||
}
|
||||
|
||||
createOpts := rds.CreateDBParameterGroupInput{
|
||||
DBParameterGroupName: aws.String(d.Get("name").(string)),
|
||||
DBParameterGroupName: aws.String(groupName),
|
||||
DBParameterGroupFamily: aws.String(d.Get("family").(string)),
|
||||
Description: aws.String(d.Get("description").(string)),
|
||||
Tags: tags,
|
||||
|
|
|
@ -3,6 +3,7 @@ package aws
|
|||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -290,6 +291,44 @@ func TestAccAWSDBParameterGroup_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBParameterGroup_namePrefix(t *testing.T) {
|
||||
var v rds.DBParameterGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBParameterGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDBParameterGroupConfig_namePrefix,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBParameterGroupExists("aws_db_parameter_group.test", &v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_db_parameter_group.test", "name", regexp.MustCompile("^tf-test-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBParameterGroup_generatedName(t *testing.T) {
|
||||
var v rds.DBParameterGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBParameterGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDBParameterGroupConfig_generatedName,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBParameterGroupExists("aws_db_parameter_group.test", &v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBParameterGroup_withApplyMethod(t *testing.T) {
|
||||
var v rds.DBParameterGroup
|
||||
|
||||
|
@ -671,3 +710,16 @@ resource "aws_db_parameter_group" "large" {
|
|||
parameter { name = "tx_isolation" value = "REPEATABLE-READ" }
|
||||
}`, n)
|
||||
}
|
||||
|
||||
const testAccDBParameterGroupConfig_namePrefix = `
|
||||
resource "aws_db_parameter_group" "test" {
|
||||
name_prefix = "tf-test-"
|
||||
family = "mysql5.6"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccDBParameterGroupConfig_generatedName = `
|
||||
resource "aws_db_parameter_group" "test" {
|
||||
family = "mysql5.6"
|
||||
}
|
||||
`
|
||||
|
|
|
@ -3,7 +3,6 @@ package aws
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -32,9 +31,18 @@ func resourceAwsDbSubnetGroup() *schema.Resource {
|
|||
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
ValidateFunc: validateSubnetGroupName,
|
||||
ConflictsWith: []string{"name_prefix"},
|
||||
ValidateFunc: validateDbSubnetGroupName,
|
||||
},
|
||||
"name_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateDbSubnetGroupNamePrefix,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
|
@ -65,8 +73,17 @@ func resourceAwsDbSubnetGroupCreate(d *schema.ResourceData, meta interface{}) er
|
|||
subnetIds[i] = aws.String(subnetId.(string))
|
||||
}
|
||||
|
||||
var groupName string
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
groupName = v.(string)
|
||||
} else if v, ok := d.GetOk("name_prefix"); ok {
|
||||
groupName = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
groupName = resource.UniqueId()
|
||||
}
|
||||
|
||||
createOpts := rds.CreateDBSubnetGroupInput{
|
||||
DBSubnetGroupName: aws.String(d.Get("name").(string)),
|
||||
DBSubnetGroupName: aws.String(groupName),
|
||||
DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
|
||||
SubnetIds: subnetIds,
|
||||
Tags: tags,
|
||||
|
@ -238,20 +255,3 @@ func buildRDSsubgrpARN(identifier, partition, accountid, region string) (string,
|
|||
return arn, nil
|
||||
|
||||
}
|
||||
|
||||
func validateSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
|
||||
}
|
||||
if len(value) > 255 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be longer than 255 characters", k))
|
||||
}
|
||||
if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q is not allowed as %q", "Default", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package aws
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
|
@ -43,6 +44,46 @@ func TestAccAWSDBSubnetGroup_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBSubnetGroup_namePrefix(t *testing.T) {
|
||||
var v rds.DBSubnetGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDBSubnetGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDBSubnetGroupConfig_namePrefix,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDBSubnetGroupExists(
|
||||
"aws_db_subnet_group.test", &v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_db_subnet_group.test", "name", regexp.MustCompile("^tf_test-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBSubnetGroup_generatedName(t *testing.T) {
|
||||
var v rds.DBSubnetGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDBSubnetGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDBSubnetGroupConfig_generatedName,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDBSubnetGroupExists(
|
||||
"aws_db_subnet_group.test", &v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/hashicorp/terraform/issues/2603 and
|
||||
// https://github.com/hashicorp/terraform/issues/2664
|
||||
func TestAccAWSDBSubnetGroup_withUndocumentedCharacters(t *testing.T) {
|
||||
|
@ -105,38 +146,6 @@ func TestAccAWSDBSubnetGroup_updateDescription(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestResourceAWSDBSubnetGroupNameValidation(t *testing.T) {
|
||||
cases := []struct {
|
||||
Value string
|
||||
ErrCount int
|
||||
}{
|
||||
{
|
||||
Value: "tEsting",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing?",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "default",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: randomString(300),
|
||||
ErrCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, errors := validateSubnetGroupName(tc.Value, "aws_db_subnet_group")
|
||||
|
||||
if len(errors) != tc.ErrCount {
|
||||
t.Fatalf("Expected the DB Subnet Group name to trigger a validation error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckDBSubnetGroupDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).rdsconn
|
||||
|
||||
|
@ -263,6 +272,49 @@ resource "aws_db_subnet_group" "foo" {
|
|||
}`, rName)
|
||||
}
|
||||
|
||||
const testAccDBSubnetGroupConfig_namePrefix = `
|
||||
resource "aws_vpc" "test" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "a" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.1.1.0/24"
|
||||
availability_zone = "us-west-2a"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "b" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.1.2.0/24"
|
||||
availability_zone = "us-west-2b"
|
||||
}
|
||||
|
||||
resource "aws_db_subnet_group" "test" {
|
||||
name_prefix = "tf_test-"
|
||||
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
|
||||
}`
|
||||
|
||||
const testAccDBSubnetGroupConfig_generatedName = `
|
||||
resource "aws_vpc" "test" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "a" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.1.1.0/24"
|
||||
availability_zone = "us-west-2a"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "b" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.1.2.0/24"
|
||||
availability_zone = "us-west-2b"
|
||||
}
|
||||
|
||||
resource "aws_db_subnet_group" "test" {
|
||||
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
|
||||
}`
|
||||
|
||||
const testAccDBSubnetGroupConfig_withUnderscoresAndPeriodsAndSpaces = `
|
||||
resource "aws_vpc" "main" {
|
||||
cidr_block = "192.168.0.0/16"
|
||||
|
|
|
@ -118,6 +118,12 @@ func resourceAwsEcsService() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
if strings.ToLower(old) == strings.ToLower(new) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -45,6 +45,7 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
|
|||
hash := sha1.Sum([]byte(v.(string)))
|
||||
return hex.EncodeToString(hash[:])
|
||||
},
|
||||
ValidateFunc: validateAwsEcsTaskDefinitionContainerDefinitions,
|
||||
},
|
||||
|
||||
"task_role_arn": {
|
||||
|
@ -121,6 +122,15 @@ func validateAwsEcsTaskDefinitionNetworkMode(v interface{}, k string) (ws []stri
|
|||
return
|
||||
}
|
||||
|
||||
func validateAwsEcsTaskDefinitionContainerDefinitions(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
_, err := expandEcsContainerDefinitions(value)
|
||||
if err != nil {
|
||||
errors = append(errors, fmt.Errorf("ECS Task Definition container_definitions is invalid: %s", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ecsconn
|
||||
|
||||
|
|
|
@ -203,6 +203,28 @@ func TestValidateAwsEcsTaskDefinitionNetworkMode(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestValidateAwsEcsTaskDefinitionContainerDefinitions(t *testing.T) {
|
||||
validDefinitions := []string{
|
||||
testValidateAwsEcsTaskDefinitionValidContainerDefinitions,
|
||||
}
|
||||
for _, v := range validDefinitions {
|
||||
_, errors := validateAwsEcsTaskDefinitionContainerDefinitions(v, "container_definitions")
|
||||
if len(errors) != 0 {
|
||||
t.Fatalf("%q should be a valid AWS ECS Task Definition Container Definitions: %q", v, errors)
|
||||
}
|
||||
}
|
||||
|
||||
invalidDefinitions := []string{
|
||||
testValidateAwsEcsTaskDefinitionInvalidCommandContainerDefinitions,
|
||||
}
|
||||
for _, v := range invalidDefinitions {
|
||||
_, errors := validateAwsEcsTaskDefinitionContainerDefinitions(v, "container_definitions")
|
||||
if len(errors) == 0 {
|
||||
t.Fatalf("%q should be an invalid AWS ECS Task Definition Container Definitions", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSEcsTaskDefinitionDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).ecsconn
|
||||
|
||||
|
@ -666,3 +688,29 @@ TASK_DEFINITION
|
|||
}
|
||||
}
|
||||
`
|
||||
|
||||
var testValidateAwsEcsTaskDefinitionValidContainerDefinitions = `
|
||||
[
|
||||
{
|
||||
"name": "sleep",
|
||||
"image": "busybox",
|
||||
"cpu": 10,
|
||||
"command": ["sleep","360"],
|
||||
"memory": 10,
|
||||
"essential": true
|
||||
}
|
||||
]
|
||||
`
|
||||
|
||||
var testValidateAwsEcsTaskDefinitionInvalidCommandContainerDefinitions = `
|
||||
[
|
||||
{
|
||||
"name": "sleep",
|
||||
"image": "busybox",
|
||||
"cpu": 10,
|
||||
"command": "sleep 360",
|
||||
"memory": 10,
|
||||
"essential": true
|
||||
}
|
||||
]
|
||||
`
|
||||
|
|
|
@ -83,6 +83,7 @@ func resourceAwsElasticSearchDomain() *schema.Resource {
|
|||
"volume_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -85,6 +85,13 @@ func testAccESDomainPolicyConfig(randInt int, policy string) string {
|
|||
resource "aws_elasticsearch_domain" "example" {
|
||||
domain_name = "tf-test-%d"
|
||||
elasticsearch_version = "2.3"
|
||||
cluster_config {
|
||||
instance_type = "t2.micro.elasticsearch"
|
||||
}
|
||||
ebs_options {
|
||||
ebs_enabled = true
|
||||
volume_size = 10
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_elasticsearch_domain_policy" "main" {
|
||||
|
|
|
@ -96,7 +96,7 @@ func TestAccAWSElasticSearchDomain_complex(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSElasticSearch_tags(t *testing.T) {
|
||||
func TestAccAWSElasticSearchDomain_tags(t *testing.T) {
|
||||
var domain elasticsearch.ElasticsearchDomainStatus
|
||||
var td elasticsearch.ListTagsOutput
|
||||
ri := acctest.RandInt()
|
||||
|
@ -198,6 +198,10 @@ func testAccESDomainConfig(randInt int) string {
|
|||
return fmt.Sprintf(`
|
||||
resource "aws_elasticsearch_domain" "example" {
|
||||
domain_name = "tf-test-%d"
|
||||
ebs_options {
|
||||
ebs_enabled = true
|
||||
volume_size = 10
|
||||
}
|
||||
}
|
||||
`, randInt)
|
||||
}
|
||||
|
@ -206,6 +210,10 @@ func testAccESDomainConfig_TagUpdate(randInt int) string {
|
|||
return fmt.Sprintf(`
|
||||
resource "aws_elasticsearch_domain" "example" {
|
||||
domain_name = "tf-test-%d"
|
||||
ebs_options {
|
||||
ebs_enabled = true
|
||||
volume_size = 10
|
||||
}
|
||||
|
||||
tags {
|
||||
foo = "bar"
|
||||
|
@ -220,6 +228,10 @@ func testAccESDomainConfig_complex(randInt int) string {
|
|||
resource "aws_elasticsearch_domain" "example" {
|
||||
domain_name = "tf-test-%d"
|
||||
|
||||
cluster_config {
|
||||
instance_type = "r3.large.elasticsearch"
|
||||
}
|
||||
|
||||
advanced_options {
|
||||
"indices.fielddata.cache.size" = 80
|
||||
}
|
||||
|
@ -248,6 +260,10 @@ func testAccESDomainConfigV23(randInt int) string {
|
|||
return fmt.Sprintf(`
|
||||
resource "aws_elasticsearch_domain" "example" {
|
||||
domain_name = "tf-test-%d"
|
||||
ebs_options {
|
||||
ebs_enabled = true
|
||||
volume_size = 10
|
||||
}
|
||||
elasticsearch_version = "2.3"
|
||||
}
|
||||
`, randInt)
|
||||
|
|
|
@ -287,7 +287,7 @@ func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
|
||||
err = resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
|
||||
_, err := elbconn.CreateLoadBalancer(elbOpts)
|
||||
|
||||
if err != nil {
|
||||
|
@ -488,7 +488,7 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
// Occasionally AWS will error with a 'duplicate listener', without any
|
||||
// other listeners on the ELB. Retry here to eliminate that.
|
||||
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
err := resource.Retry(5*time.Minute, func() *resource.RetryError {
|
||||
log.Printf("[DEBUG] ELB Create Listeners opts: %s", createListenersOpts)
|
||||
if _, err := elbconn.CreateLoadBalancerListeners(createListenersOpts); err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
|
@ -746,7 +746,7 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
log.Printf("[DEBUG] ELB attach subnets opts: %s", attachOpts)
|
||||
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
err := resource.Retry(5*time.Minute, func() *resource.RetryError {
|
||||
_, err := elbconn.AttachLoadBalancerToSubnets(attachOpts)
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
|
|
|
@ -297,14 +297,13 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
|
|||
err := resource.Retry(10*time.Minute, func() *resource.RetryError {
|
||||
_, err := conn.CreateFunction(params)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Received %q, retrying CreateFunction", err)
|
||||
if awserr, ok := err.(awserr.Error); ok {
|
||||
if awserr.Code() == "InvalidParameterValueException" {
|
||||
log.Printf("[DEBUG] InvalidParameterValueException creating Lambda Function: %s", awserr)
|
||||
return resource.RetryableError(awserr)
|
||||
}
|
||||
}
|
||||
log.Printf("[DEBUG] Error creating Lambda Function: %s", err)
|
||||
|
||||
if isAWSErr(err, "InvalidParameterValueException", "The role defined for the function cannot be assumed by Lambda") {
|
||||
log.Printf("[DEBUG] Received %s, retrying CreateFunction", err)
|
||||
return resource.RetryableError(err)
|
||||
}
|
||||
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsLightsailStaticIp() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsLightsailStaticIpCreate,
|
||||
Read: resourceAwsLightsailStaticIpRead,
|
||||
Delete: resourceAwsLightsailStaticIpDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"ip_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"support_code": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsLightsailStaticIpCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).lightsailconn
|
||||
|
||||
name := d.Get("name").(string)
|
||||
log.Printf("[INFO] Allocating Lightsail Static IP: %q", name)
|
||||
out, err := conn.AllocateStaticIp(&lightsail.AllocateStaticIpInput{
|
||||
StaticIpName: aws.String(name),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[INFO] Lightsail Static IP allocated: %s", *out)
|
||||
|
||||
d.SetId(name)
|
||||
|
||||
return resourceAwsLightsailStaticIpRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsLightsailStaticIpRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).lightsailconn
|
||||
|
||||
name := d.Get("name").(string)
|
||||
log.Printf("[INFO] Reading Lightsail Static IP: %q", name)
|
||||
out, err := conn.GetStaticIp(&lightsail.GetStaticIpInput{
|
||||
StaticIpName: aws.String(name),
|
||||
})
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "NotFoundException" {
|
||||
log.Printf("[WARN] Lightsail Static IP (%s) not found, removing from state", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Printf("[INFO] Received Lightsail Static IP: %s", *out)
|
||||
|
||||
d.Set("arn", out.StaticIp.Arn)
|
||||
d.Set("ip_address", out.StaticIp.IpAddress)
|
||||
d.Set("support_code", out.StaticIp.SupportCode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsLightsailStaticIpDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).lightsailconn
|
||||
|
||||
name := d.Get("name").(string)
|
||||
log.Printf("[INFO] Deleting Lightsail Static IP: %q", name)
|
||||
out, err := conn.ReleaseStaticIp(&lightsail.ReleaseStaticIpInput{
|
||||
StaticIpName: aws.String(name),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[INFO] Deleted Lightsail Static IP: %s", *out)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsLightsailStaticIpAttachment() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsLightsailStaticIpAttachmentCreate,
|
||||
Read: resourceAwsLightsailStaticIpAttachmentRead,
|
||||
Delete: resourceAwsLightsailStaticIpAttachmentDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"static_ip_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"instance_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsLightsailStaticIpAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).lightsailconn
|
||||
|
||||
staticIpName := d.Get("static_ip_name").(string)
|
||||
log.Printf("[INFO] Attaching Lightsail Static IP: %q", staticIpName)
|
||||
out, err := conn.AttachStaticIp(&lightsail.AttachStaticIpInput{
|
||||
StaticIpName: aws.String(staticIpName),
|
||||
InstanceName: aws.String(d.Get("instance_name").(string)),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[INFO] Lightsail Static IP attached: %s", *out)
|
||||
|
||||
d.SetId(staticIpName)
|
||||
|
||||
return resourceAwsLightsailStaticIpAttachmentRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsLightsailStaticIpAttachmentRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).lightsailconn
|
||||
|
||||
staticIpName := d.Get("static_ip_name").(string)
|
||||
log.Printf("[INFO] Reading Lightsail Static IP: %q", staticIpName)
|
||||
out, err := conn.GetStaticIp(&lightsail.GetStaticIpInput{
|
||||
StaticIpName: aws.String(staticIpName),
|
||||
})
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "NotFoundException" {
|
||||
log.Printf("[WARN] Lightsail Static IP (%s) not found, removing from state", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
if !*out.StaticIp.IsAttached {
|
||||
log.Printf("[WARN] Lightsail Static IP (%s) is not attached, removing from state", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Received Lightsail Static IP: %s", *out)
|
||||
|
||||
d.Set("instance_name", out.StaticIp.AttachedTo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsLightsailStaticIpAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).lightsailconn
|
||||
|
||||
name := d.Get("static_ip_name").(string)
|
||||
log.Printf("[INFO] Detaching Lightsail Static IP: %q", name)
|
||||
out, err := conn.DetachStaticIp(&lightsail.DetachStaticIpInput{
|
||||
StaticIpName: aws.String(name),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[INFO] Detached Lightsail Static IP: %s", *out)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSLightsailStaticIpAttachment_basic(t *testing.T) {
|
||||
var staticIp lightsail.StaticIp
|
||||
staticIpName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
instanceName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
keypairName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSLightsailStaticIpAttachmentDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSLightsailStaticIpAttachmentConfig_basic(staticIpName, instanceName, keypairName),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckAWSLightsailStaticIpAttachmentExists("aws_lightsail_static_ip_attachment.test", &staticIp),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSLightsailStaticIpAttachment_disappears(t *testing.T) {
|
||||
var staticIp lightsail.StaticIp
|
||||
staticIpName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
instanceName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
keypairName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
|
||||
staticIpDestroy := func(*terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).lightsailconn
|
||||
_, err := conn.DetachStaticIp(&lightsail.DetachStaticIpInput{
|
||||
StaticIpName: aws.String(staticIpName),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting Lightsail Static IP in disappear test")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSLightsailStaticIpAttachmentDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSLightsailStaticIpAttachmentConfig_basic(staticIpName, instanceName, keypairName),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckAWSLightsailStaticIpAttachmentExists("aws_lightsail_static_ip_attachment.test", &staticIp),
|
||||
staticIpDestroy,
|
||||
),
|
||||
ExpectNonEmptyPlan: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAWSLightsailStaticIpAttachmentExists(n string, staticIp *lightsail.StaticIp) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return errors.New("No Lightsail Static IP Attachment ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).lightsailconn
|
||||
|
||||
resp, err := conn.GetStaticIp(&lightsail.GetStaticIpInput{
|
||||
StaticIpName: aws.String(rs.Primary.ID),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp == nil || resp.StaticIp == nil {
|
||||
return fmt.Errorf("Static IP (%s) not found", rs.Primary.ID)
|
||||
}
|
||||
|
||||
if !*resp.StaticIp.IsAttached {
|
||||
return fmt.Errorf("Static IP (%s) not attached", rs.Primary.ID)
|
||||
}
|
||||
|
||||
*staticIp = *resp.StaticIp
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSLightsailStaticIpAttachmentDestroy(s *terraform.State) error {
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_lightsail_static_ip_attachment" {
|
||||
continue
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).lightsailconn
|
||||
|
||||
resp, err := conn.GetStaticIp(&lightsail.GetStaticIpInput{
|
||||
StaticIpName: aws.String(rs.Primary.ID),
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
if *resp.StaticIp.IsAttached {
|
||||
return fmt.Errorf("Lightsail Static IP %q is still attached (to %q)", rs.Primary.ID, *resp.StaticIp.AttachedTo)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the error
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "NotFoundException" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccAWSLightsailStaticIpAttachmentConfig_basic(staticIpName, instanceName, keypairName string) string {
|
||||
return fmt.Sprintf(`
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
resource "aws_lightsail_static_ip_attachment" "test" {
|
||||
static_ip_name = "${aws_lightsail_static_ip.test.name}"
|
||||
instance_name = "${aws_lightsail_instance.test.name}"
|
||||
}
|
||||
|
||||
resource "aws_lightsail_static_ip" "test" {
|
||||
name = "%s"
|
||||
}
|
||||
|
||||
resource "aws_lightsail_instance" "test" {
|
||||
name = "%s"
|
||||
availability_zone = "us-east-1b"
|
||||
blueprint_id = "wordpress_4_6_1"
|
||||
bundle_id = "micro_1_0"
|
||||
key_pair_name = "${aws_lightsail_key_pair.test.name}"
|
||||
}
|
||||
|
||||
resource "aws_lightsail_key_pair" "test" {
|
||||
name = "%s"
|
||||
}
|
||||
`, staticIpName, instanceName, keypairName)
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSLightsailStaticIp_basic(t *testing.T) {
|
||||
var staticIp lightsail.StaticIp
|
||||
staticIpName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSLightsailStaticIpDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSLightsailStaticIpConfig_basic(staticIpName),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckAWSLightsailStaticIpExists("aws_lightsail_static_ip.test", &staticIp),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSLightsailStaticIp_disappears(t *testing.T) {
|
||||
var staticIp lightsail.StaticIp
|
||||
staticIpName := fmt.Sprintf("tf-test-lightsail-%s", acctest.RandString(5))
|
||||
|
||||
staticIpDestroy := func(*terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).lightsailconn
|
||||
_, err := conn.ReleaseStaticIp(&lightsail.ReleaseStaticIpInput{
|
||||
StaticIpName: aws.String(staticIpName),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting Lightsail Static IP in disapear test")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSLightsailStaticIpDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSLightsailStaticIpConfig_basic(staticIpName),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckAWSLightsailStaticIpExists("aws_lightsail_static_ip.test", &staticIp),
|
||||
staticIpDestroy,
|
||||
),
|
||||
ExpectNonEmptyPlan: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAWSLightsailStaticIpExists(n string, staticIp *lightsail.StaticIp) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return errors.New("No Lightsail Static IP ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).lightsailconn
|
||||
|
||||
resp, err := conn.GetStaticIp(&lightsail.GetStaticIpInput{
|
||||
StaticIpName: aws.String(rs.Primary.ID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp == nil || resp.StaticIp == nil {
|
||||
return fmt.Errorf("Static IP (%s) not found", rs.Primary.ID)
|
||||
}
|
||||
*staticIp = *resp.StaticIp
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSLightsailStaticIpDestroy(s *terraform.State) error {
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_lightsail_static_ip" {
|
||||
continue
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).lightsailconn
|
||||
|
||||
resp, err := conn.GetStaticIp(&lightsail.GetStaticIpInput{
|
||||
StaticIpName: aws.String(rs.Primary.ID),
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
if resp.StaticIp != nil {
|
||||
return fmt.Errorf("Lightsail Static IP %q still exists", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the error
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() == "NotFoundException" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccAWSLightsailStaticIpConfig_basic(staticIpName string) string {
|
||||
return fmt.Sprintf(`
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
resource "aws_lightsail_static_ip" "test" {
|
||||
name = "%s"
|
||||
}
|
||||
`, staticIpName)
|
||||
}
|
|
@ -781,7 +781,7 @@ func resourceAwsOpsworksInstanceCreate(d *schema.ResourceData, meta interface{})
|
|||
d.Set("id", instanceId)
|
||||
|
||||
if v, ok := d.GetOk("state"); ok && v.(string) == "running" {
|
||||
err := startOpsworksInstance(d, meta, false)
|
||||
err := startOpsworksInstance(d, meta, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -860,7 +860,7 @@ func resourceAwsOpsworksInstanceUpdate(d *schema.ResourceData, meta interface{})
|
|||
}
|
||||
} else {
|
||||
if status != "stopped" && status != "stopping" && status != "shutting_down" {
|
||||
err := stopOpsworksInstance(d, meta, false)
|
||||
err := stopOpsworksInstance(d, meta, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -37,9 +37,18 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
|
||||
"cluster_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsId,
|
||||
ConflictsWith: []string{"cluster_identifier_prefix"},
|
||||
ValidateFunc: validateRdsIdentifier,
|
||||
},
|
||||
"cluster_identifier_prefix": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsIdentifierPrefix,
|
||||
},
|
||||
|
||||
"cluster_members": {
|
||||
|
@ -225,6 +234,19 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error
|
|||
conn := meta.(*AWSClient).rdsconn
|
||||
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
|
||||
|
||||
var identifier string
|
||||
if v, ok := d.GetOk("cluster_identifier"); ok {
|
||||
identifier = v.(string)
|
||||
} else {
|
||||
if v, ok := d.GetOk("cluster_identifier_prefix"); ok {
|
||||
identifier = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
identifier = resource.PrefixedUniqueId("tf-")
|
||||
}
|
||||
|
||||
d.Set("cluster_identifier", identifier)
|
||||
}
|
||||
|
||||
if _, ok := d.GetOk("snapshot_identifier"); ok {
|
||||
opts := rds.RestoreDBClusterFromSnapshotInput{
|
||||
DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)),
|
||||
|
|
|
@ -26,8 +26,17 @@ func resourceAwsRDSClusterInstance() *schema.Resource {
|
|||
"identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsId,
|
||||
ConflictsWith: []string{"identifier_prefix"},
|
||||
ValidateFunc: validateRdsIdentifier,
|
||||
},
|
||||
"identifier_prefix": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsIdentifierPrefix,
|
||||
},
|
||||
|
||||
"db_subnet_group_name": {
|
||||
|
@ -162,10 +171,14 @@ func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{
|
|||
createOpts.DBParameterGroupName = aws.String(attr.(string))
|
||||
}
|
||||
|
||||
if v := d.Get("identifier").(string); v != "" {
|
||||
createOpts.DBInstanceIdentifier = aws.String(v)
|
||||
if v, ok := d.GetOk("identifier"); ok {
|
||||
createOpts.DBInstanceIdentifier = aws.String(v.(string))
|
||||
} else {
|
||||
createOpts.DBInstanceIdentifier = aws.String(resource.UniqueId())
|
||||
if v, ok := d.GetOk("identifier_prefix"); ok {
|
||||
createOpts.DBInstanceIdentifier = aws.String(resource.PrefixedUniqueId(v.(string)))
|
||||
} else {
|
||||
createOpts.DBInstanceIdentifier = aws.String(resource.PrefixedUniqueId("tf-"))
|
||||
}
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("db_subnet_group_name"); ok {
|
||||
|
|
|
@ -46,6 +46,48 @@ func TestAccAWSRDSClusterInstance_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRDSClusterInstance_namePrefix(t *testing.T) {
|
||||
var v rds.DBInstance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterInstanceConfig_namePrefix(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterInstanceExists("aws_rds_cluster_instance.test", &v),
|
||||
testAccCheckAWSDBClusterInstanceAttributes(&v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_rds_cluster_instance.test", "identifier", regexp.MustCompile("^tf-cluster-instance-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRDSClusterInstance_generatedName(t *testing.T) {
|
||||
var v rds.DBInstance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterInstanceConfig_generatedName(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterInstanceExists("aws_rds_cluster_instance.test", &v),
|
||||
testAccCheckAWSDBClusterInstanceAttributes(&v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_rds_cluster_instance.test", "identifier", regexp.MustCompile("^tf-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRDSClusterInstance_kmsKey(t *testing.T) {
|
||||
var v rds.DBInstance
|
||||
keyRegex := regexp.MustCompile("^arn:aws:kms:")
|
||||
|
@ -256,6 +298,83 @@ resource "aws_db_parameter_group" "bar" {
|
|||
`, n, n, n)
|
||||
}
|
||||
|
||||
func testAccAWSClusterInstanceConfig_namePrefix(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_rds_cluster_instance" "test" {
|
||||
identifier_prefix = "tf-cluster-instance-"
|
||||
cluster_identifier = "${aws_rds_cluster.test.id}"
|
||||
instance_class = "db.r3.large"
|
||||
}
|
||||
|
||||
resource "aws_rds_cluster" "test" {
|
||||
cluster_identifier = "tf-aurora-cluster-%d"
|
||||
master_username = "root"
|
||||
master_password = "password"
|
||||
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
|
||||
skip_final_snapshot = true
|
||||
}
|
||||
|
||||
resource "aws_vpc" "test" {
|
||||
cidr_block = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "a" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.0.0/24"
|
||||
availability_zone = "us-west-2a"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "b" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.1.0/24"
|
||||
availability_zone = "us-west-2b"
|
||||
}
|
||||
|
||||
resource "aws_db_subnet_group" "test" {
|
||||
name = "tf-test-%d"
|
||||
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
|
||||
}
|
||||
`, n, n)
|
||||
}
|
||||
|
||||
func testAccAWSClusterInstanceConfig_generatedName(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_rds_cluster_instance" "test" {
|
||||
cluster_identifier = "${aws_rds_cluster.test.id}"
|
||||
instance_class = "db.r3.large"
|
||||
}
|
||||
|
||||
resource "aws_rds_cluster" "test" {
|
||||
cluster_identifier = "tf-aurora-cluster-%d"
|
||||
master_username = "root"
|
||||
master_password = "password"
|
||||
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
|
||||
skip_final_snapshot = true
|
||||
}
|
||||
|
||||
resource "aws_vpc" "test" {
|
||||
cidr_block = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "a" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.0.0/24"
|
||||
availability_zone = "us-west-2a"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "b" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.1.0/24"
|
||||
availability_zone = "us-west-2b"
|
||||
}
|
||||
|
||||
resource "aws_db_subnet_group" "test" {
|
||||
name = "tf-test-%d"
|
||||
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
|
||||
}
|
||||
`, n, n)
|
||||
}
|
||||
|
||||
func testAccAWSClusterInstanceConfigKmsKey(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
|
||||
|
|
|
@ -30,10 +30,19 @@ func resourceAwsRDSClusterParameterGroup() *schema.Resource {
|
|||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
ConflictsWith: []string{"name_prefix"},
|
||||
ValidateFunc: validateDbParamGroupName,
|
||||
},
|
||||
"name_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateDbParamGroupNamePrefix,
|
||||
},
|
||||
"family": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
|
@ -86,8 +95,17 @@ func resourceAwsRDSClusterParameterGroupCreate(d *schema.ResourceData, meta inte
|
|||
rdsconn := meta.(*AWSClient).rdsconn
|
||||
tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
|
||||
|
||||
var groupName string
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
groupName = v.(string)
|
||||
} else if v, ok := d.GetOk("name_prefix"); ok {
|
||||
groupName = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
groupName = resource.UniqueId()
|
||||
}
|
||||
|
||||
createOpts := rds.CreateDBClusterParameterGroupInput{
|
||||
DBClusterParameterGroupName: aws.String(d.Get("name").(string)),
|
||||
DBClusterParameterGroupName: aws.String(groupName),
|
||||
DBParameterGroupFamily: aws.String(d.Get("family").(string)),
|
||||
Description: aws.String(d.Get("description").(string)),
|
||||
Tags: tags,
|
||||
|
|
|
@ -3,6 +3,7 @@ package aws
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -90,6 +91,44 @@ func TestAccAWSDBClusterParameterGroup_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBClusterParameterGroup_namePrefix(t *testing.T) {
|
||||
var v rds.DBClusterParameterGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBClusterParameterGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSDBClusterParameterGroupConfig_namePrefix,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBClusterParameterGroupExists("aws_rds_cluster_parameter_group.test", &v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_rds_cluster_parameter_group.test", "name", regexp.MustCompile("^tf-test-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBClusterParameterGroup_generatedName(t *testing.T) {
|
||||
var v rds.DBClusterParameterGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSDBClusterParameterGroupDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSDBClusterParameterGroupConfig_generatedName,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSDBClusterParameterGroupExists("aws_rds_cluster_parameter_group.test", &v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSDBClusterParameterGroup_disappears(t *testing.T) {
|
||||
var v rds.DBClusterParameterGroup
|
||||
|
||||
|
@ -365,3 +404,15 @@ func testAccAWSDBClusterParameterGroupOnlyConfig(name string) string {
|
|||
family = "aurora5.6"
|
||||
}`, name)
|
||||
}
|
||||
|
||||
const testAccAWSDBClusterParameterGroupConfig_namePrefix = `
|
||||
resource "aws_rds_cluster_parameter_group" "test" {
|
||||
name_prefix = "tf-test-"
|
||||
family = "aurora5.6"
|
||||
}
|
||||
`
|
||||
const testAccAWSDBClusterParameterGroupConfig_generatedName = `
|
||||
resource "aws_rds_cluster_parameter_group" "test" {
|
||||
family = "aurora5.6"
|
||||
}
|
||||
`
|
||||
|
|
|
@ -40,6 +40,46 @@ func TestAccAWSRDSCluster_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRDSCluster_namePrefix(t *testing.T) {
|
||||
var v rds.DBCluster
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig_namePrefix(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.test", &v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_rds_cluster.test", "cluster_identifier", regexp.MustCompile("^tf-test-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRDSCluster_generatedName(t *testing.T) {
|
||||
var v rds.DBCluster
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig_generatedName(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.test", &v),
|
||||
resource.TestMatchResourceAttr(
|
||||
"aws_rds_cluster.test", "cluster_identifier", regexp.MustCompile("^tf-")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRDSCluster_takeFinalSnapshot(t *testing.T) {
|
||||
var v rds.DBCluster
|
||||
rInt := acctest.RandInt()
|
||||
|
@ -322,6 +362,71 @@ resource "aws_rds_cluster" "default" {
|
|||
}`, n)
|
||||
}
|
||||
|
||||
func testAccAWSClusterConfig_namePrefix(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_rds_cluster" "test" {
|
||||
cluster_identifier_prefix = "tf-test-"
|
||||
master_username = "root"
|
||||
master_password = "password"
|
||||
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
|
||||
skip_final_snapshot = true
|
||||
}
|
||||
|
||||
resource "aws_vpc" "test" {
|
||||
cidr_block = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "a" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.0.0/24"
|
||||
availability_zone = "us-west-2a"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "b" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.1.0/24"
|
||||
availability_zone = "us-west-2b"
|
||||
}
|
||||
|
||||
resource "aws_db_subnet_group" "test" {
|
||||
name = "tf-test-%d"
|
||||
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
|
||||
}
|
||||
`, n)
|
||||
}
|
||||
|
||||
func testAccAWSClusterConfig_generatedName(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_rds_cluster" "test" {
|
||||
master_username = "root"
|
||||
master_password = "password"
|
||||
db_subnet_group_name = "${aws_db_subnet_group.test.name}"
|
||||
skip_final_snapshot = true
|
||||
}
|
||||
|
||||
resource "aws_vpc" "test" {
|
||||
cidr_block = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "a" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.0.0/24"
|
||||
availability_zone = "us-west-2a"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "b" {
|
||||
vpc_id = "${aws_vpc.test.id}"
|
||||
cidr_block = "10.0.1.0/24"
|
||||
availability_zone = "us-west-2b"
|
||||
}
|
||||
|
||||
resource "aws_db_subnet_group" "test" {
|
||||
name = "tf-test-%d"
|
||||
subnet_ids = ["${aws_subnet.a.id}", "${aws_subnet.b.id}"]
|
||||
}
|
||||
`, n)
|
||||
}
|
||||
|
||||
func testAccAWSClusterConfigWithFinalSnapshot(n int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_rds_cluster" "default" {
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ses"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsSesDomainIdentity() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsSesDomainIdentityCreate,
|
||||
Read: resourceAwsSesDomainIdentityRead,
|
||||
Delete: resourceAwsSesDomainIdentityDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"domain": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"verification_token": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsSesDomainIdentityCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).sesConn
|
||||
|
||||
domainName := d.Get("domain").(string)
|
||||
|
||||
createOpts := &ses.VerifyDomainIdentityInput{
|
||||
Domain: aws.String(domainName),
|
||||
}
|
||||
|
||||
_, err := conn.VerifyDomainIdentity(createOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error requesting SES domain identity verification: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(domainName)
|
||||
|
||||
return resourceAwsSesDomainIdentityRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsSesDomainIdentityRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).sesConn
|
||||
|
||||
domainName := d.Id()
|
||||
d.Set("domain", domainName)
|
||||
|
||||
readOpts := &ses.GetIdentityVerificationAttributesInput{
|
||||
Identities: []*string{
|
||||
aws.String(domainName),
|
||||
},
|
||||
}
|
||||
|
||||
response, err := conn.GetIdentityVerificationAttributes(readOpts)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] Error fetching identity verification attributes for %s: %s", d.Id(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
verificationAttrs, ok := response.VerificationAttributes[domainName]
|
||||
if !ok {
|
||||
log.Printf("[WARN] Domain not listed in response when fetching verification attributes for %s", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Set("verification_token", verificationAttrs.VerificationToken)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsSesDomainIdentityDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).sesConn
|
||||
|
||||
domainName := d.Get("domain").(string)
|
||||
|
||||
deleteOpts := &ses.DeleteIdentityInput{
|
||||
Identity: aws.String(domainName),
|
||||
}
|
||||
|
||||
_, err := conn.DeleteIdentity(deleteOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting SES domain identity: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ses"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAwsSESDomainIdentity_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAwsSESDomainIdentityDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: fmt.Sprintf(
|
||||
testAccAwsSESDomainIdentityConfig,
|
||||
acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum),
|
||||
),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAwsSESDomainIdentityExists("aws_ses_domain_identity.test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAwsSESDomainIdentityDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).sesConn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_ses_domain_identity" {
|
||||
continue
|
||||
}
|
||||
|
||||
domain := rs.Primary.ID
|
||||
params := &ses.GetIdentityVerificationAttributesInput{
|
||||
Identities: []*string{
|
||||
aws.String(domain),
|
||||
},
|
||||
}
|
||||
|
||||
response, err := conn.GetIdentityVerificationAttributes(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.VerificationAttributes[domain] != nil {
|
||||
return fmt.Errorf("SES Domain Identity %s still exists. Failing!", domain)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckAwsSESDomainIdentityExists(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("SES Domain Identity not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("SES Domain Identity name not set")
|
||||
}
|
||||
|
||||
domain := rs.Primary.ID
|
||||
conn := testAccProvider.Meta().(*AWSClient).sesConn
|
||||
|
||||
params := &ses.GetIdentityVerificationAttributesInput{
|
||||
Identities: []*string{
|
||||
aws.String(domain),
|
||||
},
|
||||
}
|
||||
|
||||
response, err := conn.GetIdentityVerificationAttributes(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.VerificationAttributes[domain] == nil {
|
||||
return fmt.Errorf("SES Domain Identity %s not found in AWS", domain)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccAwsSESDomainIdentityConfig = `
|
||||
resource "aws_ses_domain_identity" "test" {
|
||||
domain = "%s.terraformtesting.com"
|
||||
}
|
||||
`
|
|
@ -60,7 +60,6 @@ func resourceAwsVpc() *schema.Resource {
|
|||
|
||||
"assign_generated_ipv6_cidr_block": {
|
||||
Type: schema.TypeBool,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
@ -178,7 +177,7 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("tags", tagsToMap(vpc.Tags))
|
||||
|
||||
for _, a := range vpc.Ipv6CidrBlockAssociationSet {
|
||||
if *a.Ipv6CidrBlockState.State == "associated" {
|
||||
if *a.Ipv6CidrBlockState.State == "associated" { //we can only ever have 1 IPv6 block associated at once
|
||||
d.Set("assign_generated_ipv6_cidr_block", true)
|
||||
d.Set("ipv6_association_id", a.AssociationId)
|
||||
d.Set("ipv6_cidr_block", a.Ipv6CidrBlock)
|
||||
|
@ -344,6 +343,68 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
d.SetPartial("enable_classiclink")
|
||||
}
|
||||
|
||||
if d.HasChange("assign_generated_ipv6_cidr_block") && !d.IsNewResource() {
|
||||
toAssign := d.Get("assign_generated_ipv6_cidr_block").(bool)
|
||||
|
||||
log.Printf("[INFO] Modifying assign_generated_ipv6_cidr_block to %#v", toAssign)
|
||||
|
||||
if toAssign {
|
||||
modifyOpts := &ec2.AssociateVpcCidrBlockInput{
|
||||
VpcId: &vpcid,
|
||||
AmazonProvidedIpv6CidrBlock: aws.Bool(toAssign),
|
||||
}
|
||||
log.Printf("[INFO] Enabling assign_generated_ipv6_cidr_block vpc attribute for %s: %#v",
|
||||
d.Id(), modifyOpts)
|
||||
resp, err := conn.AssociateVpcCidrBlock(modifyOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the CIDR to become available
|
||||
log.Printf(
|
||||
"[DEBUG] Waiting for IPv6 CIDR (%s) to become associated",
|
||||
d.Id())
|
||||
stateConf := &resource.StateChangeConf{
|
||||
Pending: []string{"associating", "disassociated"},
|
||||
Target: []string{"associated"},
|
||||
Refresh: Ipv6CidrStateRefreshFunc(conn, d.Id(), *resp.Ipv6CidrBlockAssociation.AssociationId),
|
||||
Timeout: 1 * time.Minute,
|
||||
}
|
||||
if _, err := stateConf.WaitForState(); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error waiting for IPv6 CIDR (%s) to become associated: %s",
|
||||
d.Id(), err)
|
||||
}
|
||||
} else {
|
||||
modifyOpts := &ec2.DisassociateVpcCidrBlockInput{
|
||||
AssociationId: aws.String(d.Get("ipv6_association_id").(string)),
|
||||
}
|
||||
log.Printf("[INFO] Disabling assign_generated_ipv6_cidr_block vpc attribute for %s: %#v",
|
||||
d.Id(), modifyOpts)
|
||||
if _, err := conn.DisassociateVpcCidrBlock(modifyOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the CIDR to become available
|
||||
log.Printf(
|
||||
"[DEBUG] Waiting for IPv6 CIDR (%s) to become disassociated",
|
||||
d.Id())
|
||||
stateConf := &resource.StateChangeConf{
|
||||
Pending: []string{"disassociating", "associated"},
|
||||
Target: []string{"disassociated"},
|
||||
Refresh: Ipv6CidrStateRefreshFunc(conn, d.Id(), d.Get("ipv6_association_id").(string)),
|
||||
Timeout: 1 * time.Minute,
|
||||
}
|
||||
if _, err := stateConf.WaitForState(); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error waiting for IPv6 CIDR (%s) to become disassociated: %s",
|
||||
d.Id(), err)
|
||||
}
|
||||
}
|
||||
|
||||
d.SetPartial("assign_generated_ipv6_cidr_block")
|
||||
}
|
||||
|
||||
if err := setTags(conn, d); err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
@ -412,6 +473,41 @@ func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func Ipv6CidrStateRefreshFunc(conn *ec2.EC2, id string, associationId string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
describeVpcOpts := &ec2.DescribeVpcsInput{
|
||||
VpcIds: []*string{aws.String(id)},
|
||||
}
|
||||
resp, err := conn.DescribeVpcs(describeVpcOpts)
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcID.NotFound" {
|
||||
resp = nil
|
||||
} else {
|
||||
log.Printf("Error on VPCStateRefresh: %s", err)
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
// Sometimes AWS just has consistency issues and doesn't see
|
||||
// our instance yet. Return an empty state.
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
if resp.Vpcs[0].Ipv6CidrBlockAssociationSet == nil {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
for _, association := range resp.Vpcs[0].Ipv6CidrBlockAssociationSet {
|
||||
if *association.AssociationId == associationId {
|
||||
return association, *association.Ipv6CidrBlockState.State, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
|
||||
filter1 := &ec2.Filter{
|
||||
Name: aws.String("default"),
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestAccAWSVpc_enableIpv6(t *testing.T) {
|
|||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccVpcConfigIpv6Enabled,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckVpcExists("aws_vpc.foo", &vpc),
|
||||
testAccCheckVpcCidr(&vpc, "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttr(
|
||||
|
@ -55,6 +55,34 @@ func TestAccAWSVpc_enableIpv6(t *testing.T) {
|
|||
"aws_vpc.foo", "ipv6_association_id"),
|
||||
resource.TestCheckResourceAttrSet(
|
||||
"aws_vpc.foo", "ipv6_cidr_block"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_vpc.foo", "assign_generated_ipv6_cidr_block", "true"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccVpcConfigIpv6Disabled,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckVpcExists("aws_vpc.foo", &vpc),
|
||||
testAccCheckVpcCidr(&vpc, "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_vpc.foo", "cidr_block", "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_vpc.foo", "assign_generated_ipv6_cidr_block", "false"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccVpcConfigIpv6Enabled,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckVpcExists("aws_vpc.foo", &vpc),
|
||||
testAccCheckVpcCidr(&vpc, "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_vpc.foo", "cidr_block", "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttrSet(
|
||||
"aws_vpc.foo", "ipv6_association_id"),
|
||||
resource.TestCheckResourceAttrSet(
|
||||
"aws_vpc.foo", "ipv6_cidr_block"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_vpc.foo", "assign_generated_ipv6_cidr_block", "true"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -283,6 +311,12 @@ resource "aws_vpc" "foo" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccVpcConfigIpv6Disabled = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccVpcConfigUpdate = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
|
|
|
@ -294,6 +294,11 @@ func resourceAwsVpnConnectionRead(d *schema.ResourceData, meta interface{}) erro
|
|||
}
|
||||
|
||||
vpnConnection := resp.VpnConnections[0]
|
||||
if vpnConnection == nil || *vpnConnection.State == "deleted" {
|
||||
// Seems we have lost our VPN Connection
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set attributes under the user's control.
|
||||
d.Set("vpn_gateway_id", vpnConnection.VpnGatewayId)
|
||||
|
|
|
@ -3,6 +3,7 @@ package aws
|
|||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
|
@ -13,6 +14,8 @@ import (
|
|||
)
|
||||
|
||||
func TestAccAWSVpnConnection_basic(t *testing.T) {
|
||||
var vpn ec2.VpnConnection
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_vpn_connection.foo",
|
||||
|
@ -27,6 +30,7 @@ func TestAccAWSVpnConnection_basic(t *testing.T) {
|
|||
"aws_vpn_gateway.vpn_gateway",
|
||||
"aws_customer_gateway.customer_gateway",
|
||||
"aws_vpn_connection.foo",
|
||||
&vpn,
|
||||
),
|
||||
),
|
||||
},
|
||||
|
@ -38,6 +42,7 @@ func TestAccAWSVpnConnection_basic(t *testing.T) {
|
|||
"aws_vpn_gateway.vpn_gateway",
|
||||
"aws_customer_gateway.customer_gateway",
|
||||
"aws_vpn_connection.foo",
|
||||
&vpn,
|
||||
),
|
||||
),
|
||||
},
|
||||
|
@ -46,6 +51,7 @@ func TestAccAWSVpnConnection_basic(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) {
|
||||
var vpn ec2.VpnConnection
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_vpn_connection.foo",
|
||||
|
@ -60,6 +66,7 @@ func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) {
|
|||
"aws_vpn_gateway.vpn_gateway",
|
||||
"aws_customer_gateway.customer_gateway",
|
||||
"aws_vpn_connection.foo",
|
||||
&vpn,
|
||||
),
|
||||
resource.TestCheckResourceAttr("aws_vpn_connection.foo", "static_routes_only", "false"),
|
||||
),
|
||||
|
@ -68,6 +75,74 @@ func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSVpnConnection_disappears(t *testing.T) {
|
||||
var vpn ec2.VpnConnection
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccAwsVpnConnectionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsVpnConnectionConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccAwsVpnConnection(
|
||||
"aws_vpc.vpc",
|
||||
"aws_vpn_gateway.vpn_gateway",
|
||||
"aws_customer_gateway.customer_gateway",
|
||||
"aws_vpn_connection.foo",
|
||||
&vpn,
|
||||
),
|
||||
testAccAWSVpnConnectionDisappears(&vpn),
|
||||
),
|
||||
ExpectNonEmptyPlan: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccAWSVpnConnectionDisappears(connection *ec2.VpnConnection) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
_, err := conn.DeleteVpnConnection(&ec2.DeleteVpnConnectionInput{
|
||||
VpnConnectionId: connection.VpnConnectionId,
|
||||
})
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpnConnectionID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return resource.Retry(40*time.Minute, func() *resource.RetryError {
|
||||
opts := &ec2.DescribeVpnConnectionsInput{
|
||||
VpnConnectionIds: []*string{connection.VpnConnectionId},
|
||||
}
|
||||
resp, err := conn.DescribeVpnConnections(opts)
|
||||
if err != nil {
|
||||
cgw, ok := err.(awserr.Error)
|
||||
if ok && cgw.Code() == "InvalidVpnConnectionID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
if ok && cgw.Code() == "IncorrectState" {
|
||||
return resource.RetryableError(fmt.Errorf(
|
||||
"Waiting for VPN Connection to be in the correct state: %v", connection.VpnConnectionId))
|
||||
}
|
||||
return resource.NonRetryableError(
|
||||
fmt.Errorf("Error retrieving VPN Connection: %s", err))
|
||||
}
|
||||
if *resp.VpnConnections[0].State == "deleted" {
|
||||
return nil
|
||||
}
|
||||
return resource.RetryableError(fmt.Errorf(
|
||||
"Waiting for VPN Connection: %v", connection.VpnConnectionId))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testAccAwsVpnConnectionDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
|
@ -112,7 +187,8 @@ func testAccAwsVpnConnection(
|
|||
vpcResource string,
|
||||
vpnGatewayResource string,
|
||||
customerGatewayResource string,
|
||||
vpnConnectionResource string) resource.TestCheckFunc {
|
||||
vpnConnectionResource string,
|
||||
vpnConnection *ec2.VpnConnection) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[vpnConnectionResource]
|
||||
if !ok {
|
||||
|
@ -129,7 +205,7 @@ func testAccAwsVpnConnection(
|
|||
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
_, err := ec2conn.DescribeVpnConnections(&ec2.DescribeVpnConnectionsInput{
|
||||
resp, err := ec2conn.DescribeVpnConnections(&ec2.DescribeVpnConnectionsInput{
|
||||
VpnConnectionIds: []*string{aws.String(connection.Primary.ID)},
|
||||
})
|
||||
|
||||
|
@ -137,6 +213,8 @@ func testAccAwsVpnConnection(
|
|||
return err
|
||||
}
|
||||
|
||||
*vpnConnection = *resp.VpnConnections[0]
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
|
||||
func validateRdsIdentifier(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
|
@ -33,6 +33,23 @@ func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
|
|||
return
|
||||
}
|
||||
|
||||
func validateRdsIdentifierPrefix(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only lowercase alphanumeric characters and hyphens allowed in %q", k))
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"first character of %q must be a letter", k))
|
||||
}
|
||||
if regexp.MustCompile(`--`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot contain two consecutive hyphens", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if (len(value) < 1) || (len(value) > 20) {
|
||||
|
@ -103,7 +120,27 @@ func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []er
|
|||
"%q cannot be greater than 255 characters", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateDbParamGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only lowercase alphanumeric characters and hyphens allowed in %q", k))
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"first character of %q must be a letter", k))
|
||||
}
|
||||
if regexp.MustCompile(`--`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot contain two consecutive hyphens", k))
|
||||
}
|
||||
if len(value) > 255 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be greater than 226 characters", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) {
|
||||
|
@ -1041,3 +1078,79 @@ func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
|
||||
}
|
||||
if len(value) > 255 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be longer than 255 characters", k))
|
||||
}
|
||||
if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q is not allowed as %q", "Default", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateDbSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
|
||||
}
|
||||
if len(value) > 229 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be longer than 229 characters", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"first character of %q must be a letter", k))
|
||||
}
|
||||
if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only alphanumeric characters and hyphens allowed in %q", k))
|
||||
}
|
||||
if regexp.MustCompile(`--`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot contain two consecutive hyphens", k))
|
||||
}
|
||||
if regexp.MustCompile(`-$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot end with a hyphen", k))
|
||||
}
|
||||
if len(value) > 255 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be greater than 255 characters", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateDbOptionGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"first character of %q must be a letter", k))
|
||||
}
|
||||
if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"only alphanumeric characters and hyphens allowed in %q", k))
|
||||
}
|
||||
if regexp.MustCompile(`--`).MatchString(value) {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot contain two consecutive hyphens", k))
|
||||
}
|
||||
if len(value) > 229 {
|
||||
errors = append(errors, fmt.Errorf(
|
||||
"%q cannot be greater than 229 characters", k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1785,3 +1785,131 @@ func TestValidateElbNamePrefix(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDbSubnetGroupName(t *testing.T) {
|
||||
cases := []struct {
|
||||
Value string
|
||||
ErrCount int
|
||||
}{
|
||||
{
|
||||
Value: "tEsting",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing?",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "default",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: randomString(300),
|
||||
ErrCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, errors := validateDbSubnetGroupName(tc.Value, "aws_db_subnet_group")
|
||||
|
||||
if len(errors) != tc.ErrCount {
|
||||
t.Fatalf("Expected the DB Subnet Group name to trigger a validation error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDbSubnetGroupNamePrefix(t *testing.T) {
|
||||
cases := []struct {
|
||||
Value string
|
||||
ErrCount int
|
||||
}{
|
||||
{
|
||||
Value: "tEsting",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing?",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: randomString(230),
|
||||
ErrCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, errors := validateDbSubnetGroupNamePrefix(tc.Value, "aws_db_subnet_group")
|
||||
|
||||
if len(errors) != tc.ErrCount {
|
||||
t.Fatalf("Expected the DB Subnet Group name prefix to trigger a validation error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDbOptionGroupName(t *testing.T) {
|
||||
cases := []struct {
|
||||
Value string
|
||||
ErrCount int
|
||||
}{
|
||||
{
|
||||
Value: "testing123!",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "1testing123",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing--123",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing123-",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: randomString(256),
|
||||
ErrCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, errors := validateDbOptionGroupName(tc.Value, "aws_db_option_group_name")
|
||||
|
||||
if len(errors) != tc.ErrCount {
|
||||
t.Fatalf("Expected the DB Option Group Name to trigger a validation error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDbOptionGroupNamePrefix(t *testing.T) {
|
||||
cases := []struct {
|
||||
Value string
|
||||
ErrCount int
|
||||
}{
|
||||
{
|
||||
Value: "testing123!",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "1testing123",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: "testing--123",
|
||||
ErrCount: 1,
|
||||
},
|
||||
{
|
||||
Value: randomString(230),
|
||||
ErrCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, errors := validateDbOptionGroupNamePrefix(tc.Value, "aws_db_option_group_name")
|
||||
|
||||
if len(errors) != tc.ErrCount {
|
||||
t.Fatalf("Expected the DB Option Group name prefix to trigger a validation error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
|
@ -117,8 +118,13 @@ func buildDataSourceTestProgram() (string, error) {
|
|||
return "", fmt.Errorf("failed to build test stub program: %s", err)
|
||||
}
|
||||
|
||||
gopath := os.Getenv("GOPATH")
|
||||
if gopath == "" {
|
||||
gopath = filepath.Join(os.Getenv("HOME") + "/go")
|
||||
}
|
||||
|
||||
programPath := path.Join(
|
||||
os.Getenv("GOPATH"), "bin", "tf-acc-external-data-source",
|
||||
filepath.SplitList(gopath)[0], "bin", "tf-acc-external-data-source",
|
||||
)
|
||||
return programPath, nil
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
|
||||
func resourceGithubIssueLabel() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceGithubIssueLabelCreate,
|
||||
Create: resourceGithubIssueLabelCreateOrUpdate,
|
||||
Read: resourceGithubIssueLabelRead,
|
||||
Update: resourceGithubIssueLabelUpdate,
|
||||
Update: resourceGithubIssueLabelCreateOrUpdate,
|
||||
Delete: resourceGithubIssueLabelDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
|
@ -40,22 +40,55 @@ func resourceGithubIssueLabel() *schema.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func resourceGithubIssueLabelCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
// resourceGithubIssueLabelCreateOrUpdate idempotently creates or updates an
|
||||
// issue label. Issue labels are keyed off of their "name", so pre-existing
|
||||
// issue labels result in a 422 HTTP error if they exist outside of Terraform.
|
||||
// Normally this would not be an issue, except new repositories are created with
|
||||
// a "default" set of labels, and those labels easily conflict with custom ones.
|
||||
//
|
||||
// This function will first check if the label exists, and then issue an update,
|
||||
// otherwise it will create. This is also advantageous in that we get to use the
|
||||
// same function for two schema funcs.
|
||||
|
||||
func resourceGithubIssueLabelCreateOrUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*Organization).client
|
||||
o := meta.(*Organization).name
|
||||
r := d.Get("repository").(string)
|
||||
n := d.Get("name").(string)
|
||||
c := d.Get("color").(string)
|
||||
label := github.Label{
|
||||
|
||||
label := &github.Label{
|
||||
Name: &n,
|
||||
Color: &c,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Creating label: %#v", label)
|
||||
_, resp, err := client.Issues.CreateLabel(context.TODO(), meta.(*Organization).name, r, &label)
|
||||
log.Printf("[DEBUG] Querying label existence %s/%s (%s)", o, r, n)
|
||||
existing, _, _ := client.Issues.GetLabel(context.TODO(), o, r, n)
|
||||
|
||||
if existing != nil {
|
||||
log.Printf("[DEBUG] Updating label: %s/%s (%s: %s)", o, r, n, c)
|
||||
|
||||
// Pull out the original name. If we already have a resource, this is the
|
||||
// parsed ID. If not, it's the value given to the resource.
|
||||
var oname string
|
||||
if d.Id() == "" {
|
||||
oname = n
|
||||
} else {
|
||||
_, oname = parseTwoPartID(d.Id())
|
||||
}
|
||||
|
||||
_, _, err := client.Issues.EditLabel(context.TODO(), o, r, oname, label)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("[DEBUG] Creating label: %s/%s (%s: %s)", o, r, n, c)
|
||||
_, resp, err := client.Issues.CreateLabel(context.TODO(), o, r, label)
|
||||
log.Printf("[DEBUG] Response from creating label: %s", *resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId(buildTwoPartID(&r, &n))
|
||||
|
||||
|
@ -66,6 +99,7 @@ func resourceGithubIssueLabelRead(d *schema.ResourceData, meta interface{}) erro
|
|||
client := meta.(*Organization).client
|
||||
r, n := parseTwoPartID(d.Id())
|
||||
|
||||
log.Printf("[DEBUG] Reading label: %s/%s", r, n)
|
||||
githubLabel, _, err := client.Issues.GetLabel(context.TODO(), meta.(*Organization).name, r, n)
|
||||
if err != nil {
|
||||
d.SetId("")
|
||||
|
@ -80,31 +114,12 @@ func resourceGithubIssueLabelRead(d *schema.ResourceData, meta interface{}) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
func resourceGithubIssueLabelUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*Organization).client
|
||||
r := d.Get("repository").(string)
|
||||
n := d.Get("name").(string)
|
||||
c := d.Get("color").(string)
|
||||
|
||||
_, originalName := parseTwoPartID(d.Id())
|
||||
_, _, err := client.Issues.EditLabel(context.TODO(), meta.(*Organization).name, r, originalName, &github.Label{
|
||||
Name: &n,
|
||||
Color: &c,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(buildTwoPartID(&r, &n))
|
||||
|
||||
return resourceGithubIssueLabelRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceGithubIssueLabelDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*Organization).client
|
||||
r := d.Get("repository").(string)
|
||||
n := d.Get("name").(string)
|
||||
|
||||
log.Printf("[DEBUG] Deleting label: %s/%s", r, n)
|
||||
_, err := client.Issues.DeleteLabel(context.TODO(), meta.(*Organization).name, r, n)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -32,6 +32,13 @@ func TestAccGithubIssueLabel_basic(t *testing.T) {
|
|||
testAccCheckGithubIssueLabelAttributes(&label, "bar", "FFFFFF"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccGitHubIssueLabelExistsConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGithubIssueLabelExists("github_issue_label.test", &label),
|
||||
testAccCheckGithubIssueLabelAttributes(&label, "enhancement", "FF00FF"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -134,3 +141,16 @@ resource "github_issue_label" "test" {
|
|||
color = "FFFFFF"
|
||||
}
|
||||
`, testRepo)
|
||||
|
||||
var testAccGitHubIssueLabelExistsConfig string = fmt.Sprintf(`
|
||||
// Create a repository which has the default labels
|
||||
resource "github_repository" "test" {
|
||||
name = "tf-acc-repo-label-abc1234"
|
||||
}
|
||||
|
||||
resource "github_issue_label" "test" {
|
||||
repository = "${github_repository.test.name}"
|
||||
name = "enhancement" // Important! This is a pre-created label
|
||||
color = "FF00FF"
|
||||
}
|
||||
`)
|
||||
|
|
|
@ -83,6 +83,7 @@ func Provider() terraform.ResourceProvider {
|
|||
ResourcesMap: map[string]*schema.Resource{
|
||||
"kubernetes_config_map": resourceKubernetesConfigMap(),
|
||||
"kubernetes_namespace": resourceKubernetesNamespace(),
|
||||
"kubernetes_secret": resourceKubernetesSecret(),
|
||||
},
|
||||
ConfigureFunc: providerConfigure,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
pkgApi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
api "k8s.io/kubernetes/pkg/api/v1"
|
||||
kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
)
|
||||
|
||||
func resourceKubernetesSecret() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceKubernetesSecretCreate,
|
||||
Read: resourceKubernetesSecretRead,
|
||||
Exists: resourceKubernetesSecretExists,
|
||||
Update: resourceKubernetesSecretUpdate,
|
||||
Delete: resourceKubernetesSecretDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"metadata": namespacedMetadataSchema("secret", true),
|
||||
"data": {
|
||||
Type: schema.TypeMap,
|
||||
Description: "A map of the secret data.",
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
"type": {
|
||||
Type: schema.TypeString,
|
||||
Description: "Type of secret",
|
||||
Default: "Opaque",
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceKubernetesSecretCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*kubernetes.Clientset)
|
||||
|
||||
metadata := expandMetadata(d.Get("metadata").([]interface{}))
|
||||
secret := api.Secret{
|
||||
ObjectMeta: metadata,
|
||||
StringData: expandStringMap(d.Get("data").(map[string]interface{})),
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("type"); ok {
|
||||
secret.Type = api.SecretType(v.(string))
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Creating new secret: %#v", secret)
|
||||
out, err := conn.CoreV1().Secrets(metadata.Namespace).Create(&secret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Submitting new secret: %#v", out)
|
||||
d.SetId(buildId(out.ObjectMeta))
|
||||
|
||||
return resourceKubernetesSecretRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceKubernetesSecretRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*kubernetes.Clientset)
|
||||
|
||||
namespace, name := idParts(d.Id())
|
||||
|
||||
log.Printf("[INFO] Reading secret %s", name)
|
||||
secret, err := conn.CoreV1().Secrets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Received secret: %#v", secret)
|
||||
err = d.Set("metadata", flattenMetadata(secret.ObjectMeta))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("data", byteMapToStringMap(secret.Data))
|
||||
d.Set("type", secret.Type)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceKubernetesSecretUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*kubernetes.Clientset)
|
||||
|
||||
namespace, name := idParts(d.Id())
|
||||
|
||||
ops := patchMetadata("metadata.0.", "/metadata/", d)
|
||||
if d.HasChange("data") {
|
||||
oldV, newV := d.GetChange("data")
|
||||
|
||||
oldV = base64EncodeStringMap(oldV.(map[string]interface{}))
|
||||
newV = base64EncodeStringMap(newV.(map[string]interface{}))
|
||||
|
||||
diffOps := diffStringMap("/data/", oldV.(map[string]interface{}), newV.(map[string]interface{}))
|
||||
|
||||
ops = append(ops, diffOps...)
|
||||
}
|
||||
|
||||
data, err := ops.MarshalJSON()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to marshal update operations: %s", err)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Updating secret %q: %v", name, data)
|
||||
out, err := conn.CoreV1().Secrets(namespace).Patch(name, pkgApi.JSONPatchType, data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to update secret: %s", err)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Submitting updated secret: %#v", out)
|
||||
d.SetId(buildId(out.ObjectMeta))
|
||||
|
||||
return resourceKubernetesSecretRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceKubernetesSecretDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*kubernetes.Clientset)
|
||||
|
||||
namespace, name := idParts(d.Id())
|
||||
|
||||
log.Printf("[INFO] Deleting secret: %q", name)
|
||||
err := conn.CoreV1().Secrets(namespace).Delete(name, &api.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Secret %s deleted", name)
|
||||
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceKubernetesSecretExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
conn := meta.(*kubernetes.Clientset)
|
||||
|
||||
namespace, name := idParts(d.Id())
|
||||
|
||||
log.Printf("[INFO] Checking secret %s", name)
|
||||
_, err := conn.CoreV1().Secrets(namespace).Get(name)
|
||||
if err != nil {
|
||||
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
|
||||
return false, nil
|
||||
}
|
||||
log.Printf("[DEBUG] Received error: %#v", err)
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
api "k8s.io/kubernetes/pkg/api/v1"
|
||||
kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
)
|
||||
|
||||
func TestAccKubernetesSecret_basic(t *testing.T) {
|
||||
var conf api.Secret
|
||||
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "kubernetes_secret.test",
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckKubernetesSecretDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_basic(name),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckKubernetesSecretExists("kubernetes_secret.test", &conf),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.%", "2"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.TestAnnotationOne", "one"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.TestAnnotationTwo", "two"),
|
||||
testAccCheckMetaAnnotations(&conf.ObjectMeta, map[string]string{"TestAnnotationOne": "one", "TestAnnotationTwo": "two"}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.%", "3"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.TestLabelOne", "one"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.TestLabelTwo", "two"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.TestLabelThree", "three"),
|
||||
testAccCheckMetaLabels(&conf.ObjectMeta, map[string]string{"TestLabelOne": "one", "TestLabelTwo": "two", "TestLabelThree": "three"}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.name", name),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.generation"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.resource_version"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.self_link"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.uid"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.%", "2"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.one", "first"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.two", "second"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "type", "Opaque"),
|
||||
testAccCheckSecretData(&conf, map[string]string{"one": "first", "two": "second"}),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_modified(name),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckKubernetesSecretExists("kubernetes_secret.test", &conf),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.%", "2"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.TestAnnotationOne", "one"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.Different", "1234"),
|
||||
testAccCheckMetaAnnotations(&conf.ObjectMeta, map[string]string{"TestAnnotationOne": "one", "Different": "1234"}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.%", "2"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.TestLabelOne", "one"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.TestLabelThree", "three"),
|
||||
testAccCheckMetaLabels(&conf.ObjectMeta, map[string]string{"TestLabelOne": "one", "TestLabelThree": "three"}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.name", name),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.generation"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.resource_version"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.self_link"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.uid"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.%", "3"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.one", "first"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.two", "second"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.nine", "ninth"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "type", "Opaque"),
|
||||
testAccCheckSecretData(&conf, map[string]string{"one": "first", "two": "second", "nine": "ninth"}),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_noData(name),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckKubernetesSecretExists("kubernetes_secret.test", &conf),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.%", "0"),
|
||||
testAccCheckMetaAnnotations(&conf.ObjectMeta, map[string]string{}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.%", "0"),
|
||||
testAccCheckMetaLabels(&conf.ObjectMeta, map[string]string{}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.name", name),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.generation"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.resource_version"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.self_link"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.uid"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.%", "0"),
|
||||
testAccCheckSecretData(&conf, map[string]string{}),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_typeSpecified(name),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckKubernetesSecretExists("kubernetes_secret.test", &conf),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.%", "0"),
|
||||
testAccCheckMetaAnnotations(&conf.ObjectMeta, map[string]string{}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.%", "0"),
|
||||
testAccCheckMetaLabels(&conf.ObjectMeta, map[string]string{}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.name", name),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.generation"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.resource_version"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.self_link"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.uid"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.%", "2"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.username", "admin"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "data.password", "password"),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "type", "kubernetes.io/basic-auth"),
|
||||
testAccCheckSecretData(&conf, map[string]string{"username": "admin", "password": "password"}),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccKubernetesSecret_importBasic(t *testing.T) {
|
||||
resourceName := "kubernetes_secret.test"
|
||||
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckKubernetesSecretDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_basic(name),
|
||||
},
|
||||
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccKubernetesSecret_generatedName(t *testing.T) {
|
||||
var conf api.Secret
|
||||
prefix := "tf-acc-test-gen-"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "kubernetes_secret.test",
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckKubernetesSecretDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_generatedName(prefix),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckKubernetesSecretExists("kubernetes_secret.test", &conf),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.annotations.%", "0"),
|
||||
testAccCheckMetaAnnotations(&conf.ObjectMeta, map[string]string{}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.labels.%", "0"),
|
||||
testAccCheckMetaLabels(&conf.ObjectMeta, map[string]string{}),
|
||||
resource.TestCheckResourceAttr("kubernetes_secret.test", "metadata.0.generate_name", prefix),
|
||||
resource.TestMatchResourceAttr("kubernetes_secret.test", "metadata.0.name", regexp.MustCompile("^"+prefix)),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.generation"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.resource_version"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.self_link"),
|
||||
resource.TestCheckResourceAttrSet("kubernetes_secret.test", "metadata.0.uid"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccKubernetesSecret_importGeneratedName(t *testing.T) {
|
||||
resourceName := "kubernetes_secret.test"
|
||||
prefix := "tf-acc-test-gen-import-"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckKubernetesSecretDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccKubernetesSecretConfig_generatedName(prefix),
|
||||
},
|
||||
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckSecretData(m *api.Secret, expected map[string]string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if len(expected) == 0 && len(m.Data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if !reflect.DeepEqual(byteMapToStringMap(m.Data), expected) {
|
||||
return fmt.Errorf("%s data don't match.\nExpected: %q\nGiven: %q",
|
||||
m.Name, expected, m.Data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckKubernetesSecretDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*kubernetes.Clientset)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "kubernetes_secret" {
|
||||
continue
|
||||
}
|
||||
namespace, name := idParts(rs.Primary.ID)
|
||||
resp, err := conn.CoreV1().Secrets(namespace).Get(name)
|
||||
if err == nil {
|
||||
if resp.Name == rs.Primary.ID {
|
||||
return fmt.Errorf("Secret still exists: %s", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckKubernetesSecretExists(n string, obj *api.Secret) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*kubernetes.Clientset)
|
||||
namespace, name := idParts(rs.Primary.ID)
|
||||
out, err := conn.CoreV1().Secrets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*obj = *out
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccKubernetesSecretConfig_basic(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "kubernetes_secret" "test" {
|
||||
metadata {
|
||||
annotations {
|
||||
TestAnnotationOne = "one"
|
||||
TestAnnotationTwo = "two"
|
||||
}
|
||||
labels {
|
||||
TestLabelOne = "one"
|
||||
TestLabelTwo = "two"
|
||||
TestLabelThree = "three"
|
||||
}
|
||||
name = "%s"
|
||||
}
|
||||
data {
|
||||
one = "first"
|
||||
two = "second"
|
||||
}
|
||||
}`, name)
|
||||
}
|
||||
|
||||
func testAccKubernetesSecretConfig_modified(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "kubernetes_secret" "test" {
|
||||
metadata {
|
||||
annotations {
|
||||
TestAnnotationOne = "one"
|
||||
Different = "1234"
|
||||
}
|
||||
labels {
|
||||
TestLabelOne = "one"
|
||||
TestLabelThree = "three"
|
||||
}
|
||||
name = "%s"
|
||||
}
|
||||
data {
|
||||
one = "first"
|
||||
two = "second"
|
||||
nine = "ninth"
|
||||
}
|
||||
}`, name)
|
||||
}
|
||||
|
||||
func testAccKubernetesSecretConfig_noData(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "kubernetes_secret" "test" {
|
||||
metadata {
|
||||
name = "%s"
|
||||
}
|
||||
}`, name)
|
||||
}
|
||||
|
||||
func testAccKubernetesSecretConfig_typeSpecified(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "kubernetes_secret" "test" {
|
||||
metadata {
|
||||
name = "%s"
|
||||
}
|
||||
data {
|
||||
username = "admin"
|
||||
password = "password"
|
||||
}
|
||||
type = "kubernetes.io/basic-auth"
|
||||
}`, name)
|
||||
}
|
||||
|
||||
func testAccKubernetesSecretConfig_generatedName(prefix string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "kubernetes_secret" "test" {
|
||||
metadata {
|
||||
generate_name = "%s"
|
||||
}
|
||||
data {
|
||||
one = "first"
|
||||
two = "second"
|
||||
}
|
||||
}`, prefix)
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"encoding/base64"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
api "k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
@ -99,3 +100,20 @@ func isInternalAnnotationKey(annotationKey string) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
func byteMapToStringMap(m map[string][]byte) map[string]string {
|
||||
result := make(map[string]string)
|
||||
for k, v := range m {
|
||||
result[k] = string(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func base64EncodeStringMap(m map[string]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for k, v := range m {
|
||||
value := v.(string)
|
||||
result[k] = (base64.StdEncoding.EncodeToString([]byte(value)))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/go-oracle-terraform/opc"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
User string
|
||||
Password string
|
||||
IdentityDomain string
|
||||
Endpoint string
|
||||
MaxRetryTimeout int
|
||||
}
|
||||
|
||||
type OPCClient struct {
|
||||
Client *compute.Client
|
||||
MaxRetryTimeout int
|
||||
}
|
||||
|
||||
func (c *Config) Client() (*compute.Client, error) {
|
||||
u, err := url.ParseRequestURI(c.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid endpoint URI: %s", err)
|
||||
}
|
||||
|
||||
config := opc.Config{
|
||||
IdentityDomain: &c.IdentityDomain,
|
||||
Username: &c.User,
|
||||
Password: &c.Password,
|
||||
APIEndpoint: u,
|
||||
HTTPClient: http.DefaultClient,
|
||||
}
|
||||
|
||||
// TODO: http client wrapping / log level
|
||||
return compute.NewComputeClient(&config)
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceNetworkInterface() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceNetworkInterfaceRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"instance_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"instance_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"interface": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
// Computed Values returned from the data source lookup
|
||||
"dns": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"ip_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"ip_network": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"mac_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"model": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"name_servers": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"nat": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"search_domains": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"sec_lists": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"shared_network": {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"vnic": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"vnic_sets": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).Instances()
|
||||
|
||||
// Get required attributes
|
||||
instance_name := d.Get("instance_name").(string)
|
||||
instance_id := d.Get("instance_id").(string)
|
||||
targetInterface := d.Get("interface").(string)
|
||||
|
||||
// Get instance
|
||||
input := &compute.GetInstanceInput{
|
||||
Name: instance_name,
|
||||
ID: instance_id,
|
||||
}
|
||||
|
||||
instance, err := client.GetInstance(input)
|
||||
if err != nil {
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading instance %q: %v", instance_name, err)
|
||||
}
|
||||
|
||||
result := compute.NetworkingInfo{}
|
||||
|
||||
// If the target instance has no network interfaces, return
|
||||
if instance.Networking == nil {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the computed fields
|
||||
result = instance.Networking[targetInterface]
|
||||
|
||||
// Check if the target interface exists or not
|
||||
if &result == nil {
|
||||
log.Printf("[WARN] %q networking interface not found on instance %q", targetInterface, instance_name)
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("%s-%s", instance_name, targetInterface))
|
||||
|
||||
// vNIC is a required field for an IP Network interface, and can only be set if the network
|
||||
// interface is inside an IP Network. Use this key to determine shared_network status
|
||||
if result.Vnic != "" {
|
||||
d.Set("shared_network", false)
|
||||
} else {
|
||||
d.Set("shared_network", true)
|
||||
}
|
||||
|
||||
d.Set("ip_address", result.IPAddress)
|
||||
d.Set("ip_network", result.IPNetwork)
|
||||
d.Set("mac_address", result.MACAddress)
|
||||
d.Set("model", result.Model)
|
||||
d.Set("vnic", result.Vnic)
|
||||
|
||||
if err := setStringList(d, "dns", result.DNS); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setStringList(d, "name_servers", result.NameServers); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setStringList(d, "nat", result.Nat); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setStringList(d, "search_domains", result.SearchDomains); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setStringList(d, "sec_lists", result.SecLists); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setStringList(d, "vnic_sets", result.VnicSets); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCDataSourceNetworkInterface_basic(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resName := "data.opc_compute_network_interface.test"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccDataSourceNetworkInterfaceBasic(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(resName, "ip_network", fmt.Sprintf("testing-ip-network-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "vnic", fmt.Sprintf("ip-network-test-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "shared_network", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCDataSourceNetworkInterface_sharedNetwork(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resName := "data.opc_compute_network_interface.test"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccDataSourceNetworkInterfaceShared(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(resName, "model", "e1000"),
|
||||
resource.TestCheckResourceAttr(resName, "nat.#", "1"),
|
||||
resource.TestCheckResourceAttr(resName, "shared_network", "true"),
|
||||
resource.TestCheckResourceAttr(resName, "sec_lists.#", "1"),
|
||||
resource.TestCheckResourceAttr(resName, "name_servers.#", "0"),
|
||||
resource.TestCheckResourceAttr(resName, "vnic_sets.#", "0"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccDataSourceNetworkInterfaceBasic(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_network" "foo" {
|
||||
name = "testing-ip-network-%d"
|
||||
description = "testing-ip-network-instance"
|
||||
ip_address_prefix = "10.1.12.0/24"
|
||||
}
|
||||
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "test-%d"
|
||||
label = "test"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
networking_info {
|
||||
index = 0
|
||||
ip_network = "${opc_compute_ip_network.foo.id}"
|
||||
vnic = "ip-network-test-%d"
|
||||
shared_network = false
|
||||
}
|
||||
}
|
||||
|
||||
data "opc_compute_network_interface" "test" {
|
||||
instance_name = "${opc_compute_instance.test.name}"
|
||||
instance_id = "${opc_compute_instance.test.id}"
|
||||
interface = "eth0"
|
||||
}`, rInt, rInt, rInt)
|
||||
}
|
||||
|
||||
func testAccDataSourceNetworkInterfaceShared(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "test-%d"
|
||||
label = "test"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
tags = ["tag1", "tag2"]
|
||||
networking_info {
|
||||
index = 0
|
||||
model = "e1000"
|
||||
nat = ["ippool:/oracle/public/ippool"]
|
||||
shared_network = true
|
||||
}
|
||||
}
|
||||
|
||||
data "opc_compute_network_interface" "test" {
|
||||
instance_name = "${opc_compute_instance.test.name}"
|
||||
instance_id = "${opc_compute_instance.test.id}"
|
||||
interface = "eth0"
|
||||
}`, rInt)
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceVNIC() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceVNICRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"mac_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"tags": tagsComputedSchema(),
|
||||
|
||||
"transit_flag": {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceVNICRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).VirtNICs()
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
input := &compute.GetVirtualNICInput{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
vnic, err := client.GetVirtualNIC(input)
|
||||
if err != nil {
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading vnic %s: %s", name, err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
d.Set("description", vnic.Description)
|
||||
d.Set("mac_address", vnic.MACAddress)
|
||||
d.Set("transit_flag", vnic.TransitFlag)
|
||||
d.Set("uri", vnic.Uri)
|
||||
if err := setStringList(d, "tags", vnic.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCVNIC_Basic(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccVnicBasic(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(
|
||||
"data.opc_compute_vnic.foo", "mac_address", "02:5a:cd:ec:2e:4c"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"data.opc_compute_vnic.foo", "transit_flag", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccVnicBasic(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_network" "foo" {
|
||||
name = "testing-vnic-data-%d"
|
||||
description = "testing-vnic-data"
|
||||
ip_address_prefix = "10.1.13.0/24"
|
||||
}
|
||||
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "test-%d"
|
||||
label = "test"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
networking_info {
|
||||
index = 0
|
||||
ip_network = "${opc_compute_ip_network.foo.id}"
|
||||
vnic = "test-vnic-data-%d"
|
||||
shared_network = false
|
||||
mac_address = "02:5a:cd:ec:2e:4c"
|
||||
}
|
||||
}
|
||||
|
||||
data "opc_compute_vnic" "foo" {
|
||||
name = "test-vnic-data-%d"
|
||||
}`, rInt, rInt, rInt, rInt)
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// Helper function to get a string list from the schema, and alpha-sort it
|
||||
func getStringList(d *schema.ResourceData, key string) []string {
|
||||
if _, ok := d.GetOk(key); !ok {
|
||||
return nil
|
||||
}
|
||||
l := d.Get(key).([]interface{})
|
||||
res := make([]string, len(l))
|
||||
for i, v := range l {
|
||||
res[i] = v.(string)
|
||||
}
|
||||
sort.Strings(res)
|
||||
return res
|
||||
}
|
||||
|
||||
// Helper function to set a string list in the schema, in an alpha-sorted order.
|
||||
func setStringList(d *schema.ResourceData, key string, value []string) error {
|
||||
sort.Strings(value)
|
||||
return d.Set(key, value)
|
||||
}
|
||||
|
||||
// Helper function to get an int list from the schema, and numerically sort it
|
||||
func getIntList(d *schema.ResourceData, key string) []int {
|
||||
if _, ok := d.GetOk(key); !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
l := d.Get(key).([]interface{})
|
||||
res := make([]int, len(l))
|
||||
for i, v := range l {
|
||||
res[i] = v.(int)
|
||||
}
|
||||
sort.Ints(res)
|
||||
return res
|
||||
}
|
||||
|
||||
func setIntList(d *schema.ResourceData, key string, value []int) error {
|
||||
sort.Ints(value)
|
||||
return d.Set(key, value)
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCACL_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_acl.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccACLBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckACLDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
func TestAccOPCACL_importDisabled(t *testing.T) {
|
||||
resourceName := "opc_compute_acl.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccACLDisabled, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckACLDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCImageList_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_image_list.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccImageList_basic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckImageListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCImageList_importComplete(t *testing.T) {
|
||||
resourceName := "opc_compute_image_list.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccImageList_complete, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckImageListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCInstance_importBasic(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
|
||||
resourceName := "opc_compute_instance.test"
|
||||
instanceName := fmt.Sprintf("acc-test-instance-%d", rInt)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccInstanceBasic(rInt),
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateIdPrefix: instanceName + "/",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCIPAddressPrefixSet_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_ip_address_prefix_set.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := testAccIPAddressPrefixSetBasic(ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckIPAddressPrefixSetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCIPAddressReservation_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_ip_address_reservation.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := testAccOPCIPAddressReservationConfig_Basic(ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckIPAddressReservationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
func TestAccOPCIPAddressReservation_importDisabled(t *testing.T) {
|
||||
resourceName := "opc_compute_ip_address_reservation.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := testAccOPCIPAddressReservationConfig_Basic(ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckIPAddressReservationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCIPAssociation_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_ip_association.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccIPAssociationBasic, ri, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckIPAssociationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCIPNetworkExchange_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_ip_network_exchange.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccIPNetworkExchangeBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckIPNetworkExchangeDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCIPReservation_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_ip_reservation.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccIPReservationBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckIPReservationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCRoute_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_route.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := testAccOPCRouteConfig_Basic(ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckRouteDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecRule_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_sec_rule.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecRuleBasic, ri, ri, ri, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCSecRule_importComplete(t *testing.T) {
|
||||
resourceName := "opc_compute_sec_rule.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecRuleComplete, ri, ri, ri, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecurityApplication_importICMP(t *testing.T) {
|
||||
resourceName := "opc_compute_security_application.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityApplicationICMP, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckSecurityApplicationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCSecurityApplication_importTCP(t *testing.T) {
|
||||
resourceName := "opc_compute_security_application.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityApplicationTCP, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckSecurityApplicationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecurityAssociation_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_security_association.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccSecurityAssociationBasic, ri, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckSecurityAssociationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCSecurityAssociation_importComplete(t *testing.T) {
|
||||
resourceName := "opc_compute_security_association.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccSecurityAssociationComplete, ri, ri, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckSecurityAssociationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecurityIPList_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_security_ip_list.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityIPListBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityIPListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecurityList_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_security_list.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityListBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCSecurityList_importComplete(t *testing.T) {
|
||||
resourceName := "opc_compute_security_list.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityListComplete, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecurityProtocol_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_security_protocol.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityProtocolBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityProtocolDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
func TestAccOPCSecurityProtocol_importDisabled(t *testing.T) {
|
||||
resourceName := "opc_compute_security_protocol.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSecurityProtocolFull, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityProtocolDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSecurityRule_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_security_rule.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := testAccOPCSecurityRuleConfig_Basic(ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCSecurityRule_importFull(t *testing.T) {
|
||||
resourceName := "opc_compute_security_rule.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := testAccOPCSecurityRuleConfig_Full(ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSecurityRuleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCSSHKey_importBasic(t *testing.T) {
|
||||
resourceName := "opc_compute_ssh_key.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSSHKeyBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckSSHKeyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCSSHKey_importDisabled(t *testing.T) {
|
||||
resourceName := "opc_compute_ssh_key.test"
|
||||
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccOPCSSHKeyDisabled, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckSSHKeyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func Provider() terraform.ResourceProvider {
|
||||
return &schema.Provider{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"user": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("OPC_USERNAME", nil),
|
||||
Description: "The user name for OPC API operations.",
|
||||
},
|
||||
|
||||
"password": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("OPC_PASSWORD", nil),
|
||||
Description: "The user password for OPC API operations.",
|
||||
},
|
||||
|
||||
"identity_domain": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("OPC_IDENTITY_DOMAIN", nil),
|
||||
Description: "The OPC identity domain for API operations",
|
||||
},
|
||||
|
||||
"endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("OPC_ENDPOINT", nil),
|
||||
Description: "The HTTP endpoint for OPC API operations.",
|
||||
},
|
||||
|
||||
"max_retry_timeout": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("OPC_MAX_RETRY_TIMEOUT", 3000),
|
||||
Description: "Max num seconds to wait for successful response when operating on resources within OPC (defaults to 3000)",
|
||||
},
|
||||
},
|
||||
|
||||
DataSourcesMap: map[string]*schema.Resource{
|
||||
"opc_compute_network_interface": dataSourceNetworkInterface(),
|
||||
"opc_compute_vnic": dataSourceVNIC(),
|
||||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"opc_compute_ip_network": resourceOPCIPNetwork(),
|
||||
"opc_compute_acl": resourceOPCACL(),
|
||||
"opc_compute_image_list": resourceOPCImageList(),
|
||||
"opc_compute_instance": resourceInstance(),
|
||||
"opc_compute_ip_address_reservation": resourceOPCIPAddressReservation(),
|
||||
"opc_compute_ip_association": resourceOPCIPAssociation(),
|
||||
"opc_compute_ip_network_exchange": resourceOPCIPNetworkExchange(),
|
||||
"opc_compute_ip_reservation": resourceOPCIPReservation(),
|
||||
"opc_compute_route": resourceOPCRoute(),
|
||||
"opc_compute_security_application": resourceOPCSecurityApplication(),
|
||||
"opc_compute_security_association": resourceOPCSecurityAssociation(),
|
||||
"opc_compute_security_ip_list": resourceOPCSecurityIPList(),
|
||||
"opc_compute_security_list": resourceOPCSecurityList(),
|
||||
"opc_compute_security_rule": resourceOPCSecurityRule(),
|
||||
"opc_compute_sec_rule": resourceOPCSecRule(),
|
||||
"opc_compute_ssh_key": resourceOPCSSHKey(),
|
||||
"opc_compute_storage_volume": resourceOPCStorageVolume(),
|
||||
"opc_compute_vnic_set": resourceOPCVNICSet(),
|
||||
"opc_compute_security_protocol": resourceOPCSecurityProtocol(),
|
||||
"opc_compute_ip_address_prefix_set": resourceOPCIPAddressPrefixSet(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
}
|
||||
}
|
||||
|
||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
config := Config{
|
||||
User: d.Get("user").(string),
|
||||
Password: d.Get("password").(string),
|
||||
IdentityDomain: d.Get("identity_domain").(string),
|
||||
Endpoint: d.Get("endpoint").(string),
|
||||
MaxRetryTimeout: d.Get("max_retry_timeout").(int),
|
||||
}
|
||||
|
||||
return config.Client()
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
var testAccProviders map[string]terraform.ResourceProvider
|
||||
var testAccProvider *schema.Provider
|
||||
|
||||
func init() {
|
||||
testAccProvider = Provider().(*schema.Provider)
|
||||
testAccProviders = map[string]terraform.ResourceProvider{
|
||||
"opc": testAccProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_impl(t *testing.T) {
|
||||
var _ terraform.ResourceProvider = Provider()
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
required := []string{"OPC_USERNAME", "OPC_PASSWORD", "OPC_IDENTITY_DOMAIN", "OPC_ENDPOINT"}
|
||||
for _, prop := range required {
|
||||
if os.Getenv(prop) == "" {
|
||||
t.Fatalf("%s must be set for acceptance test", prop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type OPCResourceState struct {
|
||||
*compute.Client
|
||||
*terraform.InstanceState
|
||||
}
|
||||
|
||||
func opcResourceCheck(resourceName string, f func(checker *OPCResourceState) error) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[resourceName]
|
||||
if !ok {
|
||||
return fmt.Errorf("Resource not found: %s", resourceName)
|
||||
}
|
||||
|
||||
state := &OPCResourceState{
|
||||
Client: testAccProvider.Meta().(*compute.Client),
|
||||
InstanceState: rs.Primary,
|
||||
}
|
||||
|
||||
return f(state)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceOPCACL() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCACLCreate,
|
||||
Read: resourceOPCACLRead,
|
||||
Update: resourceOPCACLUpdate,
|
||||
Delete: resourceOPCACLDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"enabled": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
"tags": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
ForceNew: true,
|
||||
},
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCACLCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] Resource state: %#v", d.State())
|
||||
|
||||
log.Print("[DEBUG] Creating acl")
|
||||
|
||||
client := meta.(*compute.Client).ACLs()
|
||||
input := compute.CreateACLInput{
|
||||
Name: d.Get("name").(string),
|
||||
Enabled: d.Get("enabled").(bool),
|
||||
}
|
||||
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.CreateACL(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating ACL: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCACLRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCACLRead(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] Resource state: %#v", d.State())
|
||||
client := meta.(*compute.Client).ACLs()
|
||||
|
||||
log.Printf("[DEBUG] Reading state of ip reservation %s", d.Id())
|
||||
getInput := compute.GetACLInput{
|
||||
Name: d.Id(),
|
||||
}
|
||||
result, err := client.GetACL(&getInput)
|
||||
if err != nil {
|
||||
// ACL does not exist
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading acl %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Read state of acl %s: %#v", d.Id(), result)
|
||||
d.Set("name", result.Name)
|
||||
d.Set("enabled", result.Enabled)
|
||||
d.Set("description", result.Description)
|
||||
d.Set("uri", result.URI)
|
||||
if err := setStringList(d, "tags", result.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCACLUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] Resource state: %#v", d.State())
|
||||
|
||||
log.Print("[DEBUG] Updating acl")
|
||||
|
||||
client := meta.(*compute.Client).ACLs()
|
||||
input := compute.UpdateACLInput{
|
||||
Name: d.Get("name").(string),
|
||||
Enabled: d.Get("enabled").(bool),
|
||||
}
|
||||
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.UpdateACL(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating ACL: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCACLRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCACLDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
log.Printf("[DEBUG] Resource state: %#v", d.State())
|
||||
client := meta.(*compute.Client).ACLs()
|
||||
name := d.Id()
|
||||
|
||||
log.Printf("[DEBUG] Deleting ACL: %v", name)
|
||||
|
||||
input := compute.DeleteACLInput{
|
||||
Name: name,
|
||||
}
|
||||
if err := client.DeleteACL(&input); err != nil {
|
||||
return fmt.Errorf("Error deleting ACL")
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCACL_Basic(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccACLBasic, ri)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckACLDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckACLExists,
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCACL_Update(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccACLBasic, ri)
|
||||
updatedConfig := fmt.Sprintf(testAccACLDisabled, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckACLDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: testAccCheckACLExists,
|
||||
},
|
||||
{
|
||||
Config: updatedConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckACLExists,
|
||||
resource.TestCheckResourceAttr("opc_compute_acl.test", "enabled", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckACLExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).ACLs()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_acl" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetACLInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if _, err := client.GetACL(&input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of ACL %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckACLDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).ACLs()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_acl" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetACLInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetACL(&input); err == nil {
|
||||
return fmt.Errorf("ACL %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccACLBasic = `
|
||||
resource "opc_compute_acl" "test" {
|
||||
name = "test_acl-%d"
|
||||
description = "test acl"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccACLDisabled = `
|
||||
resource "opc_compute_acl" "test" {
|
||||
name = "test_acl-%d"
|
||||
description = "test acl"
|
||||
enabled = false
|
||||
}
|
||||
`
|
|
@ -0,0 +1,107 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceOPCImageList() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCImageListCreate,
|
||||
Read: resourceOPCImageListRead,
|
||||
Update: resourceOPCImageListUpdate,
|
||||
Delete: resourceOPCImageListDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"default": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCImageListCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).ImageList()
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
createInput := &compute.CreateImageListInput{
|
||||
Name: name,
|
||||
Description: d.Get("description").(string),
|
||||
Default: d.Get("default").(int),
|
||||
}
|
||||
|
||||
createResult, err := client.CreateImageList(createInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(createResult.Name)
|
||||
|
||||
return resourceOPCImageListRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCImageListUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).ImageList()
|
||||
|
||||
name := d.Id()
|
||||
|
||||
updateInput := &compute.UpdateImageListInput{
|
||||
Name: name,
|
||||
Description: d.Get("description").(string),
|
||||
Default: d.Get("default").(int),
|
||||
}
|
||||
|
||||
_, err := client.UpdateImageList(updateInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceOPCImageListRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCImageListRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).ImageList()
|
||||
|
||||
getInput := &compute.GetImageListInput{
|
||||
Name: d.Id(),
|
||||
}
|
||||
getResult, err := client.GetImageList(getInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("name", getResult.Name)
|
||||
d.Set("description", getResult.Description)
|
||||
d.Set("default", getResult.Default)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCImageListDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).ImageList()
|
||||
|
||||
deleteInput := &compute.DeleteImageListInput{
|
||||
Name: d.Id(),
|
||||
}
|
||||
err := client.DeleteImageList(deleteInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCImageList_Basic(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccImageList_basic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckImageListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: testAccCheckImageListExists,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCImageList_Complete(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccImageList_complete, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckImageListDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: testAccCheckImageListExists,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckImageListExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).ImageList()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_image_list" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetImageListInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if _, err := client.GetImageList(&input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of Image List %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckImageListDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).ImageList()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_image_list" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetImageListInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetImageList(&input); err == nil {
|
||||
return fmt.Errorf("Image List %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccImageList_basic = `
|
||||
resource "opc_compute_image_list" "test" {
|
||||
name = "test-acc-image-list-basic-%d"
|
||||
description = "Image List (Basic)"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccImageList_complete = `
|
||||
resource "opc_compute_image_list" "test" {
|
||||
name = "test-acc-image-list-complete-%d"
|
||||
description = "Image List (Complete)"
|
||||
default = 2
|
||||
}
|
||||
`
|
|
@ -0,0 +1,884 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceInstance() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceInstanceCreate,
|
||||
Read: resourceInstanceRead,
|
||||
Delete: resourceInstanceDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
combined := strings.Split(d.Id(), "/")
|
||||
if len(combined) != 2 {
|
||||
return nil, fmt.Errorf("Invalid ID specified. Must be in the form of instance_name/instance_id. Got: %s", d.Id())
|
||||
}
|
||||
d.Set("name", combined[0])
|
||||
d.SetId(combined[1])
|
||||
return []*schema.ResourceData{d}, nil
|
||||
},
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
/////////////////////////
|
||||
// Required Attributes //
|
||||
/////////////////////////
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"shape": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
/////////////////////////
|
||||
// Optional Attributes //
|
||||
/////////////////////////
|
||||
"instance_attributes": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
|
||||
"boot_order": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeInt},
|
||||
},
|
||||
|
||||
"hostname": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"image_list": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"label": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"networking_info": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"dns": {
|
||||
// Required for Shared Network Interface, will default if unspecified, however
|
||||
// Optional for IP Network Interface
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"index": {
|
||||
Type: schema.TypeInt,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"ip_address": {
|
||||
// Optional, IP Network only
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"ip_network": {
|
||||
// Required for an IP Network Interface
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"mac_address": {
|
||||
// Optional, IP Network Only
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"model": {
|
||||
// Required, Shared Network only.
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
if value != "e1000" {
|
||||
errors = append(errors, fmt.Errorf("Model needs to be set to 'e1000', got: %s", value))
|
||||
}
|
||||
return
|
||||
},
|
||||
},
|
||||
|
||||
"name_servers": {
|
||||
// Optional, IP Network + Shared Network
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"nat": {
|
||||
// Optional for IP Network
|
||||
// Required for Shared Network
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"search_domains": {
|
||||
// Optional, IP Network + Shared Network
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"sec_lists": {
|
||||
// Required, Shared Network only. Will default if unspecified however
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"shared_network": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"vnic": {
|
||||
// Optional, IP Network only.
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"vnic_sets": {
|
||||
// Optional, IP Network only.
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
},
|
||||
},
|
||||
Set: func(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
buf.WriteString(fmt.Sprintf("%d-", m["index"].(int)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["vnic"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["nat"]))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["model"].(string)))
|
||||
return hashcode.String(buf.String())
|
||||
},
|
||||
},
|
||||
|
||||
"reverse_dns": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"ssh_keys": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"storage": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"index": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"volume": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"tags": tagsForceNewSchema(),
|
||||
|
||||
/////////////////////////
|
||||
// Computed Attributes //
|
||||
/////////////////////////
|
||||
"attributes": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"availability_domain": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"domain": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"entry": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"fingerprint": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"image_format": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"ip_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"placement_requirements": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"platform": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"priority": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"quota_reservation": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"relationships": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"resolvers": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"site": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"start_time": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"state": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"vcable_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"virtio": {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"vnc_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).Instances()
|
||||
|
||||
// Get Required Attributes
|
||||
input := &compute.CreateInstanceInput{
|
||||
Name: d.Get("name").(string),
|
||||
Shape: d.Get("shape").(string),
|
||||
}
|
||||
|
||||
// Get optional instance attributes
|
||||
if attributes, err := getInstanceAttributes(d); err != nil && attributes != nil {
|
||||
input.Attributes = attributes
|
||||
}
|
||||
|
||||
if bootOrder := getIntList(d, "boot_order"); len(bootOrder) > 0 {
|
||||
input.BootOrder = bootOrder
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("hostname"); ok {
|
||||
input.Hostname = v.(string)
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("image_list"); ok {
|
||||
input.ImageList = v.(string)
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("label"); ok {
|
||||
input.Label = v.(string)
|
||||
}
|
||||
|
||||
interfaces, err := readNetworkInterfacesFromConfig(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if interfaces != nil {
|
||||
input.Networking = interfaces
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("reverse_dns"); ok {
|
||||
input.ReverseDNS = v.(bool)
|
||||
}
|
||||
|
||||
if sshKeys := getStringList(d, "ssh_keys"); len(sshKeys) > 0 {
|
||||
input.SSHKeys = sshKeys
|
||||
}
|
||||
|
||||
// TODO Add storage things
|
||||
//storage := getStorageAttachments(d)
|
||||
|
||||
if tags := getStringList(d, "tags"); len(tags) > 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
result, err := client.CreateInstance(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating instance %s: %s", input.Name, err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Created instance %s: %#v", result.ID)
|
||||
|
||||
d.SetId(result.ID)
|
||||
|
||||
return resourceInstanceRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).Instances()
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
input := &compute.GetInstanceInput{
|
||||
ID: d.Id(),
|
||||
Name: name,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Reading state of instance %s", name)
|
||||
result, err := client.GetInstance(input)
|
||||
if err != nil {
|
||||
// Instance doesn't exist
|
||||
if compute.WasNotFoundError(err) {
|
||||
log.Printf("[DEBUG] Instance %s not found", name)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading instance %s: %s", name, err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Instance '%s' found", name)
|
||||
|
||||
// Update attributes
|
||||
return updateInstanceAttributes(d, result)
|
||||
}
|
||||
|
||||
func updateInstanceAttributes(d *schema.ResourceData, instance *compute.InstanceInfo) error {
|
||||
d.Set("name", instance.Name)
|
||||
d.Set("shape", instance.Shape)
|
||||
|
||||
if err := setInstanceAttributes(d, instance.Attributes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if attrs, ok := d.GetOk("instance_attributes"); ok && attrs != nil {
|
||||
d.Set("instance_attributes", attrs.(string))
|
||||
}
|
||||
|
||||
if err := setIntList(d, "boot_order", instance.BootOrder); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Set("hostname", instance.Hostname)
|
||||
d.Set("image_list", instance.ImageList)
|
||||
d.Set("label", instance.Label)
|
||||
|
||||
if err := readNetworkInterfaces(d, instance.Networking); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("reverse_dns", instance.ReverseDNS)
|
||||
if err := setStringList(d, "ssh_keys", instance.SSHKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO Set Storage
|
||||
|
||||
if err := setStringList(d, "tags", instance.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Set("availability_domain", instance.AvailabilityDomain)
|
||||
d.Set("domain", instance.Domain)
|
||||
d.Set("entry", instance.Entry)
|
||||
d.Set("fingerprint", instance.Fingerprint)
|
||||
d.Set("image_format", instance.ImageFormat)
|
||||
d.Set("ip_address", instance.IPAddress)
|
||||
|
||||
if err := setStringList(d, "placement_requirements", instance.PlacementRequirements); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("platform", instance.Platform)
|
||||
d.Set("priority", instance.Priority)
|
||||
d.Set("quota_reservation", instance.QuotaReservation)
|
||||
|
||||
if err := setStringList(d, "relationships", instance.Relationships); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setStringList(d, "resolvers", instance.Resolvers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("site", instance.Site)
|
||||
d.Set("start_time", instance.StartTime)
|
||||
d.Set("state", instance.State)
|
||||
|
||||
if err := setStringList(d, "tags", instance.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("vcable_id", instance.VCableID)
|
||||
d.Set("virtio", instance.Virtio)
|
||||
d.Set("vnc_address", instance.VNC)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceInstanceDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).Instances()
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
input := &compute.DeleteInstanceInput{
|
||||
ID: d.Id(),
|
||||
Name: name,
|
||||
}
|
||||
log.Printf("[DEBUG] Deleting instance %s", name)
|
||||
|
||||
if err := client.DeleteInstance(input); err != nil {
|
||||
return fmt.Errorf("Error deleting instance %s: %s", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO Uncomment this when working on storage
|
||||
/*
|
||||
func getStorageAttachments(d *schema.ResourceData) []compute.StorageAttachment {
|
||||
storageAttachments := []compute.StorageAttachment{}
|
||||
storage := d.Get("storage").(*schema.Set)
|
||||
for _, i := range storage.List() {
|
||||
attrs := i.(map[string]interface{})
|
||||
storageAttachments = append(storageAttachments, compute.StorageAttachmentInput{
|
||||
Index: attrs["index"].(int),
|
||||
Volume: attrs["volume"].(string),
|
||||
})
|
||||
}
|
||||
return storageAttachments
|
||||
}*/
|
||||
|
||||
// Parses instance_attributes from a string to a map[string]interface and returns any errors.
|
||||
func getInstanceAttributes(d *schema.ResourceData) (map[string]interface{}, error) {
|
||||
var attrs map[string]interface{}
|
||||
|
||||
// Empty instance attributes
|
||||
attributes, ok := d.GetOk("instance_attributes")
|
||||
if !ok {
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal([]byte(attributes.(string)), &attrs); err != nil {
|
||||
return attrs, fmt.Errorf("Cannot parse attributes as json: %s", err)
|
||||
}
|
||||
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
// Reads attributes from the returned instance object, and sets the computed attributes string
|
||||
// as JSON
|
||||
func setInstanceAttributes(d *schema.ResourceData, attributes map[string]interface{}) error {
|
||||
// Shouldn't ever get nil attributes on an instance, but protect against the case either way
|
||||
if attributes == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := json.Marshal(attributes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error marshalling returned attributes: %s", err)
|
||||
}
|
||||
return d.Set("attributes", string(b))
|
||||
}
|
||||
|
||||
// Populates and validates shared network and ip network interfaces to return the of map
|
||||
// objects needed to create/update an instance's networking_info
|
||||
func readNetworkInterfacesFromConfig(d *schema.ResourceData) (map[string]compute.NetworkingInfo, error) {
|
||||
interfaces := make(map[string]compute.NetworkingInfo)
|
||||
|
||||
if v, ok := d.GetOk("networking_info"); ok {
|
||||
vL := v.(*schema.Set).List()
|
||||
for _, v := range vL {
|
||||
ni := v.(map[string]interface{})
|
||||
index, ok := ni["index"].(int)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Index not specified for network interface: %v", ni)
|
||||
}
|
||||
|
||||
deviceIndex := fmt.Sprintf("eth%d", index)
|
||||
|
||||
// Verify that the network interface doesn't already exist
|
||||
if _, ok := interfaces[deviceIndex]; ok {
|
||||
return nil, fmt.Errorf("Duplicate Network interface at eth%d already specified", index)
|
||||
}
|
||||
|
||||
// Determine if we're creating a shared network interface or an IP Network interface
|
||||
info := compute.NetworkingInfo{}
|
||||
var err error
|
||||
if ni["shared_network"].(bool) {
|
||||
// Populate shared network parameters
|
||||
info, err = readSharedNetworkFromConfig(ni)
|
||||
} else {
|
||||
// Populate IP Network Parameters
|
||||
info, err = readIPNetworkFromConfig(ni)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// And you may find yourself in a beautiful house, with a beautiful wife
|
||||
// And you may ask yourself, well, how did I get here?
|
||||
interfaces[deviceIndex] = info
|
||||
}
|
||||
}
|
||||
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
// Reads a networking_info config block as a shared network interface
|
||||
func readSharedNetworkFromConfig(ni map[string]interface{}) (compute.NetworkingInfo, error) {
|
||||
info := compute.NetworkingInfo{}
|
||||
// Validate the shared network
|
||||
if err := validateSharedNetwork(ni); err != nil {
|
||||
return info, err
|
||||
}
|
||||
// Populate shared network fields; checking type casting
|
||||
dns := []string{}
|
||||
if v, ok := ni["dns"]; ok && v != nil {
|
||||
for _, d := range v.([]interface{}) {
|
||||
dns = append(dns, d.(string))
|
||||
}
|
||||
if len(dns) > 0 {
|
||||
info.DNS = dns
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := ni["model"].(string); ok && v != "" {
|
||||
info.Model = compute.NICModel(v)
|
||||
}
|
||||
|
||||
nats := []string{}
|
||||
if v, ok := ni["nat"]; ok && v != nil {
|
||||
for _, nat := range v.([]interface{}) {
|
||||
nats = append(nats, nat.(string))
|
||||
}
|
||||
if len(nats) > 0 {
|
||||
info.Nat = nats
|
||||
}
|
||||
}
|
||||
|
||||
slists := []string{}
|
||||
if v, ok := ni["sec_lists"]; ok && v != nil {
|
||||
for _, slist := range v.([]interface{}) {
|
||||
slists = append(slists, slist.(string))
|
||||
}
|
||||
if len(slists) > 0 {
|
||||
info.SecLists = slists
|
||||
}
|
||||
}
|
||||
|
||||
nservers := []string{}
|
||||
if v, ok := ni["name_servers"]; ok && v != nil {
|
||||
for _, nserver := range v.([]interface{}) {
|
||||
nservers = append(nservers, nserver.(string))
|
||||
}
|
||||
if len(nservers) > 0 {
|
||||
info.NameServers = nservers
|
||||
}
|
||||
}
|
||||
|
||||
sdomains := []string{}
|
||||
if v, ok := ni["search_domains"]; ok && v != nil {
|
||||
for _, sdomain := range v.([]interface{}) {
|
||||
sdomains = append(sdomains, sdomain.(string))
|
||||
}
|
||||
if len(sdomains) > 0 {
|
||||
info.SearchDomains = sdomains
|
||||
}
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// Unfortunately this cannot take place during plan-phase, because we currently cannot have a validation
|
||||
// function based off of multiple fields in the supplied schema.
|
||||
func validateSharedNetwork(ni map[string]interface{}) error {
|
||||
// A Shared Networking Interface MUST have the following attributes set:
|
||||
// - "model"
|
||||
// - "nat"
|
||||
// The following attributes _cannot_ be set for a shared network:
|
||||
// - "ip_address"
|
||||
// - "ip_network"
|
||||
// - "mac_address"
|
||||
// - "vnic"
|
||||
// - "vnic_sets"
|
||||
if d, ok := ni["model"]; !ok || d.(string) == "" {
|
||||
return fmt.Errorf("'model' field needs to be set for a Shared Networking Interface")
|
||||
}
|
||||
|
||||
if _, ok := ni["nat"]; !ok {
|
||||
return fmt.Errorf("'nat' field needs to be set for a Shared Networking Interface")
|
||||
}
|
||||
|
||||
// Strings only
|
||||
nilAttrs := []string{
|
||||
"ip_address",
|
||||
"ip_network",
|
||||
"mac_address",
|
||||
"vnic",
|
||||
}
|
||||
|
||||
for _, v := range nilAttrs {
|
||||
if d, ok := ni[v]; ok && d.(string) != "" {
|
||||
return fmt.Errorf("%q field cannot be set in a Shared Networking Interface", v)
|
||||
}
|
||||
}
|
||||
if _, ok := ni["vnic_sets"].([]string); ok {
|
||||
return fmt.Errorf("%q field cannot be set in a Shared Networking Interface", "vnic_sets")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Populates fields for an IP Network
|
||||
func readIPNetworkFromConfig(ni map[string]interface{}) (compute.NetworkingInfo, error) {
|
||||
info := compute.NetworkingInfo{}
|
||||
// Validate the IP Network
|
||||
if err := validateIPNetwork(ni); err != nil {
|
||||
return info, err
|
||||
}
|
||||
// Populate fields
|
||||
if v, ok := ni["ip_network"].(string); ok && v != "" {
|
||||
info.IPNetwork = v
|
||||
}
|
||||
|
||||
dns := []string{}
|
||||
if v, ok := ni["dns"]; ok && v != nil {
|
||||
for _, d := range v.([]interface{}) {
|
||||
dns = append(dns, d.(string))
|
||||
}
|
||||
if len(dns) > 0 {
|
||||
info.DNS = dns
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := ni["ip_address"].(string); ok && v != "" {
|
||||
info.IPAddress = v
|
||||
}
|
||||
|
||||
if v, ok := ni["mac_address"].(string); ok && v != "" {
|
||||
info.MACAddress = v
|
||||
}
|
||||
|
||||
nservers := []string{}
|
||||
if v, ok := ni["name_servers"]; ok && v != nil {
|
||||
for _, nserver := range v.([]interface{}) {
|
||||
nservers = append(nservers, nserver.(string))
|
||||
}
|
||||
if len(nservers) > 0 {
|
||||
info.NameServers = nservers
|
||||
}
|
||||
}
|
||||
|
||||
nats := []string{}
|
||||
if v, ok := ni["nat"]; ok && v != nil {
|
||||
for _, nat := range v.([]interface{}) {
|
||||
nats = append(nats, nat.(string))
|
||||
}
|
||||
if len(nats) > 0 {
|
||||
info.Nat = nats
|
||||
}
|
||||
}
|
||||
|
||||
sdomains := []string{}
|
||||
if v, ok := ni["search_domains"]; ok && v != nil {
|
||||
for _, sdomain := range v.([]interface{}) {
|
||||
sdomains = append(sdomains, sdomain.(string))
|
||||
}
|
||||
if len(sdomains) > 0 {
|
||||
info.SearchDomains = sdomains
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := ni["vnic"].(string); ok && v != "" {
|
||||
info.Vnic = v
|
||||
}
|
||||
|
||||
vnicSets := []string{}
|
||||
if v, ok := ni["vnic_sets"]; ok && v != nil {
|
||||
for _, vnic := range v.([]interface{}) {
|
||||
vnicSets = append(vnicSets, vnic.(string))
|
||||
}
|
||||
if len(vnicSets) > 0 {
|
||||
info.VnicSets = vnicSets
|
||||
}
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// Validates an IP Network config block
|
||||
func validateIPNetwork(ni map[string]interface{}) error {
|
||||
// An IP Networking Interface MUST have the following attributes set:
|
||||
// - "ip_network"
|
||||
// The following attributes _cannot_ be set for an IP Network:
|
||||
// - "model"
|
||||
|
||||
// Required to be set
|
||||
if d, ok := ni["ip_network"]; !ok || d.(string) == "" {
|
||||
return fmt.Errorf("'ip_network' field is required for an IP Network interface")
|
||||
}
|
||||
|
||||
// Requird to be unset
|
||||
if d, ok := ni["model"]; ok && d.(string) != "" {
|
||||
return fmt.Errorf("'model' cannot be set in an IP Network Interface")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reads network interfaces from the config
|
||||
func readNetworkInterfaces(d *schema.ResourceData, ifaces map[string]compute.NetworkingInfo) error {
|
||||
result := make([]map[string]interface{}, 0)
|
||||
|
||||
// Nil check for import case
|
||||
if ifaces == nil {
|
||||
return d.Set("networking_info", result)
|
||||
}
|
||||
|
||||
for _, iface := range ifaces {
|
||||
res := make(map[string]interface{})
|
||||
if iface.DNS != nil {
|
||||
res["dns"] = iface.DNS
|
||||
}
|
||||
if iface.IPAddress != "" {
|
||||
res["ip_address"] = iface.IPAddress
|
||||
}
|
||||
if iface.IPNetwork != "" {
|
||||
res["ip_network"] = iface.IPNetwork
|
||||
}
|
||||
if iface.MACAddress != "" {
|
||||
res["mac_address"] = iface.MACAddress
|
||||
}
|
||||
if iface.Model != "" {
|
||||
res["model"] = iface.Model
|
||||
// Model can only be set on Shared networks
|
||||
res["shared_network"] = true
|
||||
}
|
||||
if iface.NameServers != nil {
|
||||
res["name_servers"] = iface.NameServers
|
||||
}
|
||||
if iface.Nat != nil {
|
||||
res["nat"] = iface.Nat
|
||||
}
|
||||
if iface.SearchDomains != nil {
|
||||
res["search_domains"] = iface.SearchDomains
|
||||
}
|
||||
if iface.SecLists != nil {
|
||||
res["sec_lists"] = iface.SecLists
|
||||
}
|
||||
if iface.Vnic != "" {
|
||||
res["vnic"] = iface.Vnic
|
||||
// VNIC can only be set on an IP Network
|
||||
res["shared_network"] = false
|
||||
}
|
||||
if iface.VnicSets != nil {
|
||||
res["vnic_sets"] = iface.VnicSets
|
||||
}
|
||||
|
||||
result = append(result, res)
|
||||
}
|
||||
|
||||
return d.Set("networking_info", result)
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCInstance_basic(t *testing.T) {
|
||||
resName := "opc_compute_instance.test"
|
||||
rInt := acctest.RandInt()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccInstanceBasic(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccOPCCheckInstanceExists,
|
||||
resource.TestCheckResourceAttr(resName, "name", fmt.Sprintf("acc-test-instance-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "label", "TestAccOPCInstance_basic"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCInstance_sharedNetworking(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resName := "opc_compute_instance.test"
|
||||
dataName := "data.opc_compute_network_interface.test"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccInstanceSharedNetworking(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccOPCCheckInstanceExists,
|
||||
resource.TestCheckResourceAttrSet(resName, "id"),
|
||||
resource.TestCheckResourceAttrSet(resName, "availability_domain"),
|
||||
resource.TestCheckResourceAttrSet(resName, "domain"),
|
||||
resource.TestCheckResourceAttrSet(resName, "hostname"),
|
||||
resource.TestCheckResourceAttrSet(resName, "ip_address"),
|
||||
resource.TestCheckResourceAttr(resName, "name", fmt.Sprintf("acc-test-instance-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "networking_info.#", "1"),
|
||||
// Default Placement Reqs
|
||||
resource.TestCheckResourceAttr(resName, "placement_requirements.#", "2"),
|
||||
resource.TestCheckResourceAttr(resName, "placement_requirements.0", "/system/compute/allow_instances"),
|
||||
resource.TestCheckResourceAttr(resName, "placement_requirements.1", "/system/compute/placement/default"),
|
||||
resource.TestCheckResourceAttr(resName, "platform", "linux"),
|
||||
resource.TestCheckResourceAttr(resName, "priority", "/oracle/public/default"),
|
||||
resource.TestCheckResourceAttr(resName, "reverse_dns", "true"),
|
||||
resource.TestCheckResourceAttr(resName, "state", "running"),
|
||||
resource.TestCheckResourceAttr(resName, "tags.#", "2"),
|
||||
resource.TestCheckResourceAttrSet(resName, "vcable_id"),
|
||||
resource.TestCheckResourceAttr(resName, "virtio", "false"),
|
||||
|
||||
// Check Data Source to validate networking attributes
|
||||
resource.TestCheckResourceAttr(dataName, "shared_network", "true"),
|
||||
resource.TestCheckResourceAttr(dataName, "nat.#", "1"),
|
||||
resource.TestCheckResourceAttr(dataName, "model", "e1000"),
|
||||
resource.TestCheckResourceAttr(dataName, "sec_lists.#", "1"),
|
||||
resource.TestCheckResourceAttr(dataName, "name_servers.#", "0"),
|
||||
resource.TestCheckResourceAttr(dataName, "vnic_sets.#", "0"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccOPCInstance_ipNetwork(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resName := "opc_compute_instance.test"
|
||||
dataName := "data.opc_compute_network_interface.test"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccInstanceIPNetworking(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccOPCCheckInstanceExists,
|
||||
resource.TestCheckResourceAttrSet(resName, "id"),
|
||||
resource.TestCheckResourceAttrSet(resName, "availability_domain"),
|
||||
resource.TestCheckResourceAttrSet(resName, "domain"),
|
||||
resource.TestCheckResourceAttrSet(resName, "ip_address"),
|
||||
resource.TestCheckResourceAttr(resName, "name", fmt.Sprintf("acc-test-instance-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "networking_info.#", "1"),
|
||||
// Default Placement Reqs
|
||||
resource.TestCheckResourceAttr(resName, "placement_requirements.#", "2"),
|
||||
resource.TestCheckResourceAttr(resName, "placement_requirements.0", "/system/compute/allow_instances"),
|
||||
resource.TestCheckResourceAttr(resName, "placement_requirements.1", "/system/compute/placement/default"),
|
||||
resource.TestCheckResourceAttr(resName, "platform", "linux"),
|
||||
resource.TestCheckResourceAttr(resName, "priority", "/oracle/public/default"),
|
||||
resource.TestCheckResourceAttr(resName, "reverse_dns", "true"),
|
||||
resource.TestCheckResourceAttr(resName, "state", "running"),
|
||||
resource.TestCheckResourceAttr(resName, "virtio", "false"),
|
||||
|
||||
// Check Data Source to validate networking attributes
|
||||
resource.TestCheckResourceAttr(dataName, "ip_network", fmt.Sprintf("testing-ip-network-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(dataName, "vnic", fmt.Sprintf("ip-network-test-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(dataName, "shared_network", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccOPCCheckInstanceExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).Instances()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_instance" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := &compute.GetInstanceInput{
|
||||
ID: rs.Primary.ID,
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
_, err := client.GetInstance(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving state of Instance %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccOPCCheckInstanceDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).Instances()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_instance" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := &compute.GetInstanceInput{
|
||||
ID: rs.Primary.ID,
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetInstance(input); err == nil {
|
||||
return fmt.Errorf("Instance %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const validSSHKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqw6JwbjIkZEr5UcMojtxhk6Zum39NOihHNXEvRWDt5WssX8TH/ghpv3D25K1pJkf+wfAi17HwEmYwPMEyEHENS443v6RZbXvzCkUWzkJzq7Zvbdqld038km31La2QUoMMp1KL5zk1nM65xCeQDVcR/h++03EScB2CuzTpAV6khMdfgOJgxm361kfrDVRwc1HQrAOpOnzkpPfwqBrYWqN1UnKvuO77Wk8z5LBe03EPNru3bLE3s3qHI9hjO0gXMiVUi0KyNxdWfDO8esqQlKavHAeePyrRA55YF8kBB5dEl4tVNOqpY/8TRnGN1mOe0LWxa8Ytz1wbyS49knsNVTel"
|
||||
|
||||
func testAccInstanceBasic(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "acc-test-instance-%d"
|
||||
label = "TestAccOPCInstance_basic"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
instance_attributes = <<JSON
|
||||
{
|
||||
"foo" = "bar"
|
||||
}
|
||||
JSON
|
||||
}`, rInt)
|
||||
}
|
||||
|
||||
func testAccInstanceSharedNetworking(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "acc-test-instance-%d"
|
||||
label = "TestAccOPCInstance_sharedNetworking"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
tags = ["tag1", "tag2"]
|
||||
networking_info {
|
||||
index = 0
|
||||
model = "e1000"
|
||||
nat = ["ippool:/oracle/public/ippool"]
|
||||
shared_network = true
|
||||
}
|
||||
}
|
||||
|
||||
data "opc_compute_network_interface" "test" {
|
||||
instance_name = "${opc_compute_instance.test.name}"
|
||||
instance_id = "${opc_compute_instance.test.id}"
|
||||
interface = "eth0"
|
||||
}
|
||||
`, rInt)
|
||||
}
|
||||
|
||||
func testAccInstanceIPNetworking(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_network" "foo" {
|
||||
name = "testing-ip-network-%d"
|
||||
description = "testing-ip-network-instance"
|
||||
ip_address_prefix = "10.1.12.0/24"
|
||||
}
|
||||
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "acc-test-instance-%d"
|
||||
label = "TestAccOPCInstance_ipNetwork"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
networking_info {
|
||||
index = 0
|
||||
ip_network = "${opc_compute_ip_network.foo.id}"
|
||||
vnic = "ip-network-test-%d"
|
||||
shared_network = false
|
||||
}
|
||||
}
|
||||
|
||||
data "opc_compute_network_interface" "test" {
|
||||
instance_id = "${opc_compute_instance.test.id}"
|
||||
instance_name = "${opc_compute_instance.test.name}"
|
||||
interface = "eth0"
|
||||
}
|
||||
`, rInt, rInt, rInt)
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceOPCIPAddressPrefixSet() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCIPAddressPrefixSetCreate,
|
||||
Read: resourceOPCIPAddressPrefixSetRead,
|
||||
Update: resourceOPCIPAddressPrefixSetUpdate,
|
||||
Delete: resourceOPCIPAddressPrefixSetDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"prefixes": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ValidateFunc: validateIPPrefixCIDR,
|
||||
},
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"tags": tagsOptionalSchema(),
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressPrefixSetCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressPrefixSets()
|
||||
|
||||
input := compute.CreateIPAddressPrefixSetInput{
|
||||
Name: d.Get("name").(string),
|
||||
}
|
||||
|
||||
prefixes := getStringList(d, "prefixes")
|
||||
if len(prefixes) != 0 {
|
||||
input.IPAddressPrefixes = prefixes
|
||||
}
|
||||
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.CreateIPAddressPrefixSet(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IP Address Prefix Set: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCIPAddressPrefixSetRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressPrefixSetRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressPrefixSets()
|
||||
|
||||
getInput := compute.GetIPAddressPrefixSetInput{
|
||||
Name: d.Id(),
|
||||
}
|
||||
result, err := client.GetIPAddressPrefixSet(&getInput)
|
||||
if err != nil {
|
||||
// IP Address Prefix Set does not exist
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IP Address Prefix Set %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
d.Set("name", result.Name)
|
||||
d.Set("description", result.Description)
|
||||
d.Set("uri", result.Uri)
|
||||
if err := setStringList(d, "prefixes", result.IPAddressPrefixes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setStringList(d, "tags", result.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressPrefixSetUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressPrefixSets()
|
||||
|
||||
input := compute.UpdateIPAddressPrefixSetInput{
|
||||
Name: d.Get("name").(string),
|
||||
}
|
||||
|
||||
prefixes := getStringList(d, "prefixes")
|
||||
if len(prefixes) != 0 {
|
||||
input.IPAddressPrefixes = prefixes
|
||||
}
|
||||
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.UpdateIPAddressPrefixSet(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating IP Address Prefix Set: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCIPAddressPrefixSetRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressPrefixSetDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressPrefixSets()
|
||||
name := d.Id()
|
||||
|
||||
input := compute.DeleteIPAddressPrefixSetInput{
|
||||
Name: name,
|
||||
}
|
||||
if err := client.DeleteIPAddressPrefixSet(&input); err != nil {
|
||||
return fmt.Errorf("Error deleting IP Address Prefix Set: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCIPAddressPrefixSet_Basic(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resourceName := "opc_compute_ip_address_prefix_set.test"
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckIPAddressPrefixSetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccIPAddressPrefixSetBasic(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckIPAddressPrefixSetExists,
|
||||
resource.TestCheckResourceAttr(
|
||||
resourceName, "tags.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
resourceName, "prefixes.#", "2"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccIPAddressPrefixSetBasic_Update(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(
|
||||
resourceName, "tags.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
resourceName, "prefixes.0", "171.120.0.0/24"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckIPAddressPrefixSetExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPAddressPrefixSets()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_address_prefix_set" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPAddressPrefixSetInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if _, err := client.GetIPAddressPrefixSet(&input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of IP Address Prefix Set %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckIPAddressPrefixSetDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPAddressPrefixSets()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_address_prefix_set" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPAddressPrefixSetInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetIPAddressPrefixSet(&input); err == nil {
|
||||
return fmt.Errorf("IP Address Prefix Set %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccIPAddressPrefixSetBasic(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_address_prefix_set" "test" {
|
||||
name = "testing-acc-%d"
|
||||
prefixes = ["172.120.0.0/24", "192.168.0.0/16"]
|
||||
description = "acctesting ip address prefix test %d"
|
||||
tags = ["tag1", "tag2"]
|
||||
}`, rInt, rInt)
|
||||
}
|
||||
|
||||
func testAccIPAddressPrefixSetBasic_Update(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_address_prefix_set" "test" {
|
||||
name = "testing-acc-%d"
|
||||
description = "acctesting ip address prefix test updated %d"
|
||||
prefixes = ["171.120.0.0/24", "192.168.0.0/16"]
|
||||
tags = ["tag1"]
|
||||
}`, rInt, rInt)
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
)
|
||||
|
||||
func resourceOPCIPAddressReservation() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCIPAddressReservationCreate,
|
||||
Read: resourceOPCIPAddressReservationRead,
|
||||
Update: resourceOPCIPAddressReservationUpdate,
|
||||
Delete: resourceOPCIPAddressReservationDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"ip_address_pool": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validation.StringInSlice([]string{
|
||||
string(compute.PublicIPAddressPool),
|
||||
string(compute.PrivateIPAddressPool),
|
||||
}, true),
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"tags": tagsOptionalSchema(),
|
||||
"ip_address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressReservationCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressReservations()
|
||||
|
||||
input := compute.CreateIPAddressReservationInput{
|
||||
Name: d.Get("name").(string),
|
||||
IPAddressPool: d.Get("ip_address_pool").(string),
|
||||
}
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.CreateIPAddressReservation(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IP Address Reservation: %s", err)
|
||||
}
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCIPAddressReservationRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressReservationRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressReservations()
|
||||
|
||||
getInput := compute.GetIPAddressReservationInput{
|
||||
Name: d.Id(),
|
||||
}
|
||||
result, err := client.GetIPAddressReservation(&getInput)
|
||||
if err != nil {
|
||||
// IP Address Reservation does not exist
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading ip address reservation %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
d.Set("name", result.Name)
|
||||
d.Set("description", result.Description)
|
||||
d.Set("ip_address_pool", result.IPAddressPool)
|
||||
d.Set("uri", result.Uri)
|
||||
|
||||
if err := setStringList(d, "tags", result.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressReservationUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressReservations()
|
||||
|
||||
input := compute.UpdateIPAddressReservationInput{
|
||||
Name: d.Get("name").(string),
|
||||
IPAddressPool: d.Get("ip_address_pool").(string),
|
||||
}
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.UpdateIPAddressReservation(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating IP Address Reservation: %s", err)
|
||||
}
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCIPAddressReservationRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPAddressReservationDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAddressReservations()
|
||||
name := d.Id()
|
||||
|
||||
input := compute.DeleteIPAddressReservationInput{
|
||||
Name: name,
|
||||
}
|
||||
if err := client.DeleteIPAddressReservation(&input); err != nil {
|
||||
return fmt.Errorf("Error deleting IP Address Reservation: %+v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCIPAddressReservation_Basic(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resName := "opc_compute_ip_address_reservation.test"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckIPAddressReservationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccOPCIPAddressReservationConfig_Basic(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccOPCCheckIPAddressReservationExists,
|
||||
resource.TestCheckResourceAttr(resName, "name", fmt.Sprintf("testing-ip-address-reservation-%d", rInt)),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccOPCCheckIPAddressReservationExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPAddressReservations()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_address_reservation" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPAddressReservationInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if _, err := client.GetIPAddressReservation(&input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of IP Address Reservation %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func testAccOPCCheckIPAddressReservationDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPAddressReservations()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_address_reservation" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPAddressReservationInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetIPAddressReservation(&input); err == nil {
|
||||
return fmt.Errorf("IP Address Reservation %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccOPCIPAddressReservationConfig_Basic(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_address_reservation" "test" {
|
||||
name = "testing-ip-address-reservation-%d"
|
||||
description = "testing-desc-%d"
|
||||
ip_address_pool = "public-ippool"
|
||||
}`, rInt, rInt)
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceOPCIPAssociation() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCIPAssociationCreate,
|
||||
Read: resourceOPCIPAssociationRead,
|
||||
Delete: resourceOPCIPAssociationDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"vcable": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"parent_pool": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCIPAssociationCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
vCable := d.Get("vcable").(string)
|
||||
parentPool := d.Get("parent_pool").(string)
|
||||
|
||||
client := meta.(*compute.Client).IPAssociations()
|
||||
input := compute.CreateIPAssociationInput{
|
||||
ParentPool: parentPool,
|
||||
VCable: vCable,
|
||||
}
|
||||
info, err := client.CreateIPAssociation(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating ip association between vcable %s and parent pool %s: %s", vCable, parentPool, err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
|
||||
return resourceOPCIPAssociationRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPAssociationRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAssociations()
|
||||
|
||||
name := d.Id()
|
||||
input := compute.GetIPAssociationInput{
|
||||
Name: name,
|
||||
}
|
||||
result, err := client.GetIPAssociation(&input)
|
||||
if err != nil {
|
||||
// IP Association does not exist
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading ip association '%s': %s", name, err)
|
||||
}
|
||||
|
||||
d.Set("name", result.Name)
|
||||
d.Set("parent_pool", result.ParentPool)
|
||||
d.Set("vcable", result.VCable)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCIPAssociationDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPAssociations()
|
||||
|
||||
name := d.Id()
|
||||
input := compute.DeleteIPAssociationInput{
|
||||
Name: name,
|
||||
}
|
||||
if err := client.DeleteIPAssociation(&input); err != nil {
|
||||
return fmt.Errorf("Error deleting ip association '%s': %s", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCIPAssociation_Basic(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccIPAssociationBasic, ri, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccOPCCheckIPAssociationDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccOPCCheckIPAssociationExists,
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccOPCCheckIPAssociationExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPAssociations()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_association" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPAssociationInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if _, err := client.GetIPAssociation(&input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of IP Association %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccOPCCheckIPAssociationDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPAssociations()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_association" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPAssociationInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetIPAssociation(&input); err == nil {
|
||||
return fmt.Errorf("IP Association %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccIPAssociationBasic = `
|
||||
resource "opc_compute_instance" "test" {
|
||||
name = "test-acc-ip-ass-instance-%d"
|
||||
label = "testAccIPAssociationBasic"
|
||||
shape = "oc3"
|
||||
image_list = "/oracle/public/oel_6.7_apaas_16.4.5_1610211300"
|
||||
}
|
||||
|
||||
resource "opc_compute_ip_reservation" "test" {
|
||||
name = "test-acc-ip-ass-reservation-%d"
|
||||
parent_pool = "/oracle/public/ippool"
|
||||
permanent = true
|
||||
}
|
||||
|
||||
resource "opc_compute_ip_association" "test" {
|
||||
vcable = "${opc_compute_instance.test.vcable_id}"
|
||||
parent_pool = "ipreservation:${opc_compute_ip_reservation.test.name}"
|
||||
}
|
||||
`
|
|
@ -0,0 +1,176 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceOPCIPNetwork() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCIPNetworkCreate,
|
||||
Read: resourceOPCIPNetworkRead,
|
||||
Update: resourceOPCIPNetworkUpdate,
|
||||
Delete: resourceOPCIPNetworkDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"ip_address_prefix": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ValidateFunc: validateIPPrefixCIDR,
|
||||
},
|
||||
|
||||
"ip_network_exchange": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"public_napt_enabled": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"tags": tagsOptionalSchema(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworks()
|
||||
|
||||
// Get required attributes
|
||||
name := d.Get("name").(string)
|
||||
ipPrefix := d.Get("ip_address_prefix").(string)
|
||||
// public_napt_enabled is not required, but bool type allows it to be unspecified
|
||||
naptEnabled := d.Get("public_napt_enabled").(bool)
|
||||
|
||||
input := &compute.CreateIPNetworkInput{
|
||||
Name: name,
|
||||
IPAddressPrefix: ipPrefix,
|
||||
PublicNaptEnabled: naptEnabled,
|
||||
}
|
||||
|
||||
// Get Optional attributes
|
||||
if desc, ok := d.GetOk("description"); ok && desc != nil {
|
||||
input.Description = desc.(string)
|
||||
}
|
||||
|
||||
if ipEx, ok := d.GetOk("ip_network_exchange"); ok && ipEx != nil {
|
||||
input.IPNetworkExchange = ipEx.(string)
|
||||
}
|
||||
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
info, err := client.CreateIPNetwork(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IP Network '%s': %v", name, err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
|
||||
return resourceOPCIPNetworkRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworks()
|
||||
|
||||
name := d.Id()
|
||||
input := &compute.GetIPNetworkInput{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
res, err := client.GetIPNetwork(input)
|
||||
if err != nil {
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IP Network '%s': %v", name, err)
|
||||
}
|
||||
|
||||
d.Set("name", res.Name)
|
||||
d.Set("ip_address_prefix", res.IPAddressPrefix)
|
||||
d.Set("ip_network_exchanged", res.IPNetworkExchange)
|
||||
d.Set("description", res.Description)
|
||||
d.Set("public_napt_enabled", res.PublicNaptEnabled)
|
||||
d.Set("uri", res.Uri)
|
||||
if err := setStringList(d, "tags", res.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworks()
|
||||
|
||||
// Get required attributes
|
||||
name := d.Get("name").(string)
|
||||
ipPrefix := d.Get("ip_address_prefix").(string)
|
||||
// public_napt_enabled is not required, but bool type allows it to be unspecified
|
||||
naptEnabled := d.Get("public_napt_enabled").(bool)
|
||||
|
||||
input := &compute.UpdateIPNetworkInput{
|
||||
Name: name,
|
||||
IPAddressPrefix: ipPrefix,
|
||||
PublicNaptEnabled: naptEnabled,
|
||||
}
|
||||
|
||||
// Get Optional attributes
|
||||
desc, descOk := d.GetOk("description")
|
||||
if descOk {
|
||||
input.Description = desc.(string)
|
||||
}
|
||||
|
||||
ipEx, ipExOk := d.GetOk("ip_network_exchange")
|
||||
if ipExOk {
|
||||
input.IPNetworkExchange = ipEx.(string)
|
||||
}
|
||||
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
info, err := client.UpdateIPNetwork(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating IP Network '%s': %v", name, err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
|
||||
return resourceOPCIPNetworkRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworks()
|
||||
|
||||
name := d.Id()
|
||||
input := &compute.DeleteIPNetworkInput{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
if err := client.DeleteIPNetwork(input); err != nil {
|
||||
return fmt.Errorf("Error deleting IP Network '%s': %v", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceOPCIPNetworkExchange() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceOPCIPNetworkExchangeCreate,
|
||||
Read: resourceOPCIPNetworkExchangeRead,
|
||||
Delete: resourceOPCIPNetworkExchangeDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"tags": tagsForceNewSchema(),
|
||||
"uri": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkExchangeCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworkExchanges()
|
||||
input := compute.CreateIPNetworkExchangeInput{
|
||||
Name: d.Get("name").(string),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Creating ip network exchange '%s'", input.Name)
|
||||
tags := getStringList(d, "tags")
|
||||
if len(tags) != 0 {
|
||||
input.Tags = tags
|
||||
}
|
||||
|
||||
if description, ok := d.GetOk("description"); ok {
|
||||
input.Description = description.(string)
|
||||
}
|
||||
|
||||
info, err := client.CreateIPNetworkExchange(&input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IP Network Exchange: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(info.Name)
|
||||
return resourceOPCIPNetworkExchangeRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkExchangeRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworkExchanges()
|
||||
|
||||
log.Printf("[DEBUG] Reading state of IP Network Exchange %s", d.Id())
|
||||
getInput := compute.GetIPNetworkExchangeInput{
|
||||
Name: d.Id(),
|
||||
}
|
||||
result, err := client.GetIPNetworkExchange(&getInput)
|
||||
if err != nil {
|
||||
// IP NetworkExchange does not exist
|
||||
if compute.WasNotFoundError(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading ip network exchange %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
d.Set("name", result.Name)
|
||||
d.Set("description", result.Description)
|
||||
d.Set("uri", result.Uri)
|
||||
|
||||
if err := setStringList(d, "tags", result.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceOPCIPNetworkExchangeDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*compute.Client).IPNetworkExchanges()
|
||||
name := d.Id()
|
||||
|
||||
log.Printf("[DEBUG] Deleting IP Network Exchange '%s'", name)
|
||||
input := compute.DeleteIPNetworkExchangeInput{
|
||||
Name: name,
|
||||
}
|
||||
if err := client.DeleteIPNetworkExchange(&input); err != nil {
|
||||
return fmt.Errorf("Error deleting IP Network Exchange '%s': %+v", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccOPCIPNetworkExchange_Basic(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccIPNetworkExchangeBasic, ri)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckIPNetworkExchangeDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: testAccCheckIPNetworkExchangeExists,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckIPNetworkExchangeExists(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPNetworkExchanges()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_network_exchange" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPNetworkExchangeInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if _, err := client.GetIPNetworkExchange(&input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of ip network exchange %s: %s", input.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckIPNetworkExchangeDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*compute.Client).IPNetworkExchanges()
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "opc_compute_ip_network_exchange" {
|
||||
continue
|
||||
}
|
||||
|
||||
input := compute.GetIPNetworkExchangeInput{
|
||||
Name: rs.Primary.Attributes["name"],
|
||||
}
|
||||
if info, err := client.GetIPNetworkExchange(&input); err == nil {
|
||||
return fmt.Errorf("IPNetworkExchange %s still exists: %#v", input.Name, info)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccIPNetworkExchangeBasic = `
|
||||
resource "opc_compute_ip_network_exchange" "test" {
|
||||
name = "test_ip_network_exchange-%d"
|
||||
description = "test ip network exchange"
|
||||
}
|
||||
`
|
|
@ -0,0 +1,91 @@
|
|||
package opc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-oracle-terraform/compute"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccOPCIPNetwork_Basic(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resName := "opc_compute_ip_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: opcResourceCheck(resName, testAccOPCCheckIPNetworkDestroyed),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccOPCIPNetworkConfig_Basic(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
opcResourceCheck(resName, testAccOPCCheckIPNetworkExists),
|
||||
resource.TestCheckResourceAttr(resName, "ip_address_prefix", "10.0.12.0/24"),
|
||||
resource.TestCheckResourceAttr(resName, "public_napt_enabled", "false"),
|
||||
resource.TestCheckResourceAttr(resName, "description", fmt.Sprintf("testing-desc-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "name", fmt.Sprintf("testing-ip-network-%d", rInt)),
|
||||
resource.TestMatchResourceAttr(resName, "uri", regexp.MustCompile("testing-ip-network")),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccOPCIPNetworkConfig_BasicUpdate(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
opcResourceCheck(resName, testAccOPCCheckIPNetworkExists),
|
||||
resource.TestCheckResourceAttr(resName, "ip_address_prefix", "10.0.12.0/24"),
|
||||
resource.TestCheckResourceAttr(resName, "public_napt_enabled", "true"),
|
||||
resource.TestCheckResourceAttr(resName, "description", fmt.Sprintf("testing-desc-%d", rInt)),
|
||||
resource.TestCheckResourceAttr(resName, "name", fmt.Sprintf("testing-ip-network-%d", rInt)),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccOPCIPNetworkConfig_Basic(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_network" "foo" {
|
||||
name = "testing-ip-network-%d"
|
||||
description = "testing-desc-%d"
|
||||
ip_address_prefix = "10.0.12.0/24"
|
||||
}`, rInt, rInt)
|
||||
}
|
||||
|
||||
func testAccOPCIPNetworkConfig_BasicUpdate(rInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "opc_compute_ip_network" "foo" {
|
||||
name = "testing-ip-network-%d"
|
||||
description = "testing-desc-%d"
|
||||
ip_address_prefix = "10.0.12.0/24"
|
||||
public_napt_enabled = true
|
||||
}`, rInt, rInt)
|
||||
}
|
||||
|
||||
func testAccOPCCheckIPNetworkExists(state *OPCResourceState) error {
|
||||
name := state.Attributes["name"]
|
||||
|
||||
input := &compute.GetIPNetworkInput{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
if _, err := state.Client.IPNetworks().GetIPNetwork(input); err != nil {
|
||||
return fmt.Errorf("Error retrieving state of IP Network '%s': %v", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccOPCCheckIPNetworkDestroyed(state *OPCResourceState) error {
|
||||
name := state.Attributes["name"]
|
||||
|
||||
input := &compute.GetIPNetworkInput{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
if info, _ := state.Client.IPNetworks().GetIPNetwork(input); info != nil {
|
||||
return fmt.Errorf("IP Network '%s' still exists: %+v", name, info)
|
||||
}
|
||||
return nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue