diff --git a/builtin/providers/oracleopc/config.go b/builtin/providers/oracleopc/config.go new file mode 100644 index 000000000..fbae3b5d5 --- /dev/null +++ b/builtin/providers/oracleopc/config.go @@ -0,0 +1,47 @@ +package opc + +import ( + "fmt" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "net/url" +) + +type Config struct { + User string + Password string + IdentityDomain string + Endpoint string + MaxRetryTimeout int +} + +type storageAttachment struct { + index int + instanceName *compute.InstanceName +} + +type OPCClient struct { + *compute.AuthenticatedClient + MaxRetryTimeout int + storageAttachmentsByVolumeCache map[string][]storageAttachment +} + +func (c *Config) Client() (*OPCClient, error) { + u, err := url.ParseRequestURI(c.Endpoint) + if err != nil { + return nil, fmt.Errorf("Invalid endpoint URI: %s", err) + } + + client := compute.NewComputeClient(c.IdentityDomain, c.User, c.Password, u) + authenticatedClient, err := client.Authenticate() + if err != nil { + return nil, fmt.Errorf("Authentication failed: %s", err) + } + + opcClient := &OPCClient{ + AuthenticatedClient: authenticatedClient, + MaxRetryTimeout: c.MaxRetryTimeout, + storageAttachmentsByVolumeCache: make(map[string][]storageAttachment), + } + + return opcClient, nil +} diff --git a/builtin/providers/oracleopc/provider.go b/builtin/providers/oracleopc/provider.go new file mode 100644 index 000000000..a6d0d3fb5 --- /dev/null +++ b/builtin/providers/oracleopc/provider.go @@ -0,0 +1,75 @@ +package opc + +import ( + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +// Provider returns a terraform.ResourceProvider. +func Provider() terraform.ResourceProvider { + return &schema.Provider{ + Schema: map[string]*schema.Schema{ + "user": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OPC_USERNAME", nil), + Description: "The user name for OPC API operations.", + }, + + "password": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OPC_PASSWORD", nil), + Description: "The user password for OPC API operations.", + }, + + "identityDomain": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OPC_IDENTITY_DOMAIN", nil), + Description: "The OPC identity domain for API operations", + }, + + "endpoint": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OPC_ENDPOINT", nil), + Description: "The HTTP endpoint for OPC API operations.", + }, + + "maxRetryTimeout": &schema.Schema{ + 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)", + }, + }, + + ResourcesMap: map[string]*schema.Resource{ + "opc_compute_storage_volume": resourceStorageVolume(), + "opc_compute_instance": resourceInstance(), + "opc_compute_ssh_key": resourceSSHKey(), + "opc_compute_security_application": resourceSecurityApplication(), + "opc_compute_security_list": resourceSecurityList(), + "opc_compute_security_ip_list": resourceSecurityIPList(), + "opc_compute_ip_reservation": resourceIPReservation(), + "opc_compute_ip_association": resourceIPAssociation(), + "opc_compute_security_rule": resourceSecurityRule(), + "opc_compute_security_association": resourceSecurityAssociation(), + }, + + ConfigureFunc: providerConfigure, + } +} + +func providerConfigure(d *schema.ResourceData) (interface{}, error) { + config := Config{ + User: d.Get("user").(string), + Password: d.Get("password").(string), + IdentityDomain: d.Get("identityDomain").(string), + Endpoint: d.Get("endpoint").(string), + MaxRetryTimeout: d.Get("maxRetryTimeout").(int), + } + + return config.Client() +} diff --git a/builtin/providers/oracleopc/provider_test.go b/builtin/providers/oracleopc/provider_test.go new file mode 100644 index 000000000..c60076b06 --- /dev/null +++ b/builtin/providers/oracleopc/provider_test.go @@ -0,0 +1,61 @@ +package opc + +import ( + "os" + "testing" + + "fmt" + "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 { + *OPCClient + *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{ + OPCClient: testAccProvider.Meta().(*OPCClient), + InstanceState: rs.Primary, + } + + return f(state) + } +} diff --git a/builtin/providers/oracleopc/resource_instance.go b/builtin/providers/oracleopc/resource_instance.go new file mode 100644 index 000000000..70f3b99c8 --- /dev/null +++ b/builtin/providers/oracleopc/resource_instance.go @@ -0,0 +1,306 @@ +package opc + +import ( + "encoding/json" + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceInstance() *schema.Resource { + return &schema.Resource{ + Create: resourceInstanceCreate, + Read: resourceInstanceRead, + Delete: resourceInstanceDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "shape": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "imageList": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "label": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "ip": { + Type: schema.TypeString, + Optional: false, + Computed: true, + }, + + "opcId": { + Type: schema.TypeString, + Optional: false, + Computed: true, + }, + + "sshKeys": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "attributes": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "vcable": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "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, + }, + }, + }, + }, + + "bootOrder": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + }, + }, + } +} + +func getAttrs(d *schema.ResourceData) (*map[string]interface{}, error) { + var attrs map[string]interface{} + + attrString := d.Get("attributes").(string) + if attrString == "" { + return &attrs, nil + } + if err := json.Unmarshal([]byte(attrString), &attrs); err != nil { + return &attrs, fmt.Errorf("Cannot parse '%s' as json", attrString) + } + return &attrs, nil +} + +func resourceInstanceCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d.State()) + + client := meta.(*OPCClient).Instances() + name := d.Get("name").(string) + shape := d.Get("shape").(string) + imageList := d.Get("imageList").(string) + label := d.Get("label").(string) + storage := getStorageAttachments(d) + sshKeys := getSSHKeys(d) + bootOrder := getBootOrder(d) + + attrs, err := getAttrs(d) + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating instance with name %s, shape %s, imageList %s, storage %s, bootOrder %s, label %s, sshKeys %s, attrs %#v", + name, shape, imageList, storage, bootOrder, label, sshKeys, attrs) + + id, err := client.LaunchInstance(name, label, shape, imageList, storage, bootOrder, sshKeys, *attrs) + if err != nil { + return fmt.Errorf("Error creating instance %s: %s", name, err) + } + + log.Printf("[DEBUG] Waiting for instance %s to come online", id.String()) + info, err := client.WaitForInstanceRunning(id, meta.(*OPCClient).MaxRetryTimeout) + if err != nil { + return fmt.Errorf("Error waiting for instance %s to come online: %s", id, err) + } + + log.Printf("[DEBUG] Created instance %s: %#v", id, info) + + attachStorage( + &compute.InstanceName{ + Name: info.Name, + ID: info.ID, + }, + d, meta) + + d.SetId(info.Name) + updateInstanceResourceData(d, info) + return nil +} + +func attachStorage(name *compute.InstanceName, d *schema.ResourceData, meta interface{}) error { + storageClient := meta.(*OPCClient).StorageAttachments() + storage := d.Get("storage").(*schema.Set) + updatedStorage := schema.NewSet(storage.F, []interface{}{}) + + for _, i := range storage.List() { + attrs := i.(map[string]interface{}) + attachmentInfo, err := storageClient.CreateStorageAttachment( + attrs["index"].(int), + name, + attrs["volume"].(string)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Waiting for storage attachment %#v to come online", attachmentInfo) + storageClient.WaitForStorageAttachmentCreated(attachmentInfo.Name, meta.(*OPCClient).MaxRetryTimeout) + log.Printf("[DEBUG] Storage attachment %s: %s-%s created", + attachmentInfo.Name, attachmentInfo.InstanceName, attachmentInfo.StorageVolumeName) + attrs["name"] = attachmentInfo.Name + updatedStorage.Add(attrs) + } + + d.Set("storage", updatedStorage) + return nil +} + +func getSSHKeys(d *schema.ResourceData) []string { + sshKeys := []string{} + for _, i := range d.Get("sshKeys").([]interface{}) { + sshKeys = append(sshKeys, i.(string)) + } + return sshKeys +} + +func getBootOrder(d *schema.ResourceData) []int { + bootOrder := []int{} + for _, i := range d.Get("bootOrder").([]interface{}) { + bootOrder = append(bootOrder, i.(int)) + } + return bootOrder +} + +func getStorageAttachments(d *schema.ResourceData) []compute.LaunchPlanStorageAttachmentSpec { + storageAttachments := []compute.LaunchPlanStorageAttachmentSpec{} + storage := d.Get("storage").(*schema.Set) + for _, i := range storage.List() { + attrs := i.(map[string]interface{}) + storageAttachments = append(storageAttachments, compute.LaunchPlanStorageAttachmentSpec{ + Index: attrs["index"].(int), + Volume: attrs["volume"].(string), + }) + } + return storageAttachments +} + +func updateInstanceResourceData(d *schema.ResourceData, info *compute.InstanceInfo) error { + d.Set("name", info.Name) + d.Set("opcId", info.ID) + d.Set("imageList", info.ImageList) + d.Set("bootOrder", info.BootOrder) + d.Set("sshKeys", info.SSHKeys) + d.Set("label", info.Label) + d.Set("ip", info.IPAddress) + d.Set("vcable", info.VCableID) + + return nil +} + +func resourceInstanceRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d.State()) + client := meta.(*OPCClient).Instances() + name := d.Get("name").(string) + instanceName := &compute.InstanceName{ + Name: name, + ID: d.Get("opcId").(string), + } + + log.Printf("[DEBUG] Reading state of instance %s", instanceName) + result, err := client.GetInstance(instanceName) + if err != nil { + // Instance doesn't exist + if compute.WasNotFoundError(err) { + log.Printf("[DEBUG] Instance %s not found", instanceName) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading instance %s: %s", instanceName, err) + } + + log.Printf("[DEBUG] Read state of instance %s: %#v", instanceName, result) + + attachments, err := meta.(*OPCClient).StorageAttachments().GetStorageAttachmentsForInstance(instanceName) + if err != nil { + return fmt.Errorf("Error reading storage attachments for instance %s: %s", instanceName, err) + } + updateInstanceResourceData(d, result) + updateAttachmentResourceData(d, attachments) + return nil +} + +func updateAttachmentResourceData(d *schema.ResourceData, attachments *[]compute.StorageAttachmentInfo) { + attachmentSet := schema.NewSet(d.Get("storage").(*schema.Set).F, []interface{}{}) + for _, attachment := range *attachments { + properties := map[string]interface{}{ + "index": attachment.Index, + "volume": attachment.StorageVolumeName, + "name": attachment.Name, + } + attachmentSet.Add(properties) + } + d.Set("storage", attachmentSet) +} + +func resourceInstanceDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d.State()) + client := meta.(*OPCClient).Instances() + name := d.Get("name").(string) + + instanceName := &compute.InstanceName{ + Name: name, + ID: d.Get("opcId").(string), + } + + log.Printf("[DEBUG] Deleting instance %s", instanceName) + if err := client.DeleteInstance(instanceName); err != nil { + return fmt.Errorf("Error deleting instance %s: %s", instanceName, err) + } + if err := client.WaitForInstanceDeleted(instanceName, meta.(*OPCClient).MaxRetryTimeout); err != nil { + return fmt.Errorf("Error deleting instance %s: %s", instanceName, err) + } + + for _, attachment := range d.Get("storage").(*schema.Set).List() { + name := attachment.(map[string]interface{})["name"].(string) + log.Printf("[DEBUG] Deleting storage attachment %s", name) + client.StorageAttachments().DeleteStorageAttachment(name) + client.StorageAttachments().WaitForStorageAttachmentDeleted(name, meta.(*OPCClient).MaxRetryTimeout) + } + + return nil +} diff --git a/builtin/providers/oracleopc/resource_instance_test.go b/builtin/providers/oracleopc/resource_instance_test.go new file mode 100644 index 000000000..6f386af84 --- /dev/null +++ b/builtin/providers/oracleopc/resource_instance_test.go @@ -0,0 +1,156 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "testing" +) + +func TestAccOPCInstance_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: opcResourceCheck( + instanceResourceName, + testAccCheckInstanceDestroyed), + Steps: []resource.TestStep{ + { + Config: testAccInstanceBasic, + Check: resource.ComposeTestCheckFunc( + opcResourceCheck( + instanceResourceName, + testAccCheckInstanceExists), + opcResourceCheck( + keyResourceName, + testAccCheckSSHKeyExists), + ), + }, + { + Config: modifySSHKey, + Check: resource.ComposeTestCheckFunc( + opcResourceCheck( + instanceResourceName, + testAccCheckInstanceExists), + opcResourceCheck( + keyResourceName, + testAccCheckSSHKeyUpdated), + ), + }, + }, + }) +} + +func testAccCheckInstanceExists(state *OPCResourceState) error { + instanceName := getInstanceName(state) + + if _, err := state.Instances().GetInstance(instanceName); err != nil { + return fmt.Errorf("Error retrieving state of instance %s: %s", instanceName, err) + } + + return nil +} + +func testAccCheckSSHKeyExists(state *OPCResourceState) error { + keyName := state.Attributes["name"] + + if _, err := state.SSHKeys().GetSSHKey(keyName); err != nil { + return fmt.Errorf("Error retrieving state of key %s: %s", keyName, err) + } + + return nil +} + +func testAccCheckSSHKeyUpdated(state *OPCResourceState) error { + keyName := state.Attributes["name"] + info, err := state.SSHKeys().GetSSHKey(keyName) + if err != nil { + return err + } + if info.Key != updatedKey { + return fmt.Errorf("Expected key\n\t%s\nbut was\n\t%s", updatedKey, info.Key) + } + return nil +} + +func getInstanceName(rs *OPCResourceState) *compute.InstanceName { + return &compute.InstanceName{ + Name: rs.Attributes["name"], + ID: rs.Attributes["opcId"], + } +} + +func testAccCheckInstanceDestroyed(state *OPCResourceState) error { + instanceName := getInstanceName(state) + if info, err := state.Instances().GetInstance(instanceName); err == nil { + return fmt.Errorf("Instance %s still exists: %#v", instanceName, info) + } + + return nil +} + +const instanceName = "test_instance" +const keyName = "test_key" + +var instanceResourceName = fmt.Sprintf("opc_compute_instance.%s", instanceName) +var keyResourceName = fmt.Sprintf("opc_compute_ssh_key.%s", keyName) + +const originalKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqw6JwbjIkZEr5UcMojtxhk6Zum39NOihHNXEvRWDt5WssX8TH/ghpv3D25K1pJkf+wfAi17HwEmYwPMEyEHENS443v6RZbXvzCkUWzkJzq7Zvbdqld038km31La2QUoMMp1KL5zk1nM65xCeQDVcR/h++03EScB2CuzTpAV6khMdfgOJgxm361kfrDVRwc1HQrAOpOnzkpPfwqBrYWqN1UnKvuO77Wk8z5LBe03EPNru3bLE3s3qHI9hjO0gXMiVUi0KyNxdWfDO8esqQlKavHAeePyrRA55YF8kBB5dEl4tVNOqpY/8TRnGN1mOe0LWxa8Ytz1wbyS49knsNVTel" +const updatedKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDHvb/2OSemgzUYLNW1/T3u33r7sZy1qbWtgVWiREH4gS5TVmDVPuvN1MFLdNqiWQA53gK8Gp24jtjNm9ftcPhicv81HVWJTB69C0sJGEfF0l4mgbemJLH3i37Mb6SdWJcGof9qHVDADPgiC8jIBVUhdiJSeq4fUJ3NQA2eUExBkRglQWairkNzPNA0mi3GL9KDGnoBnSCAXNGoKgDgIOqW0dYFP6oHyGWkF7V+/TME9aIQvmMpHjVzl7brZ/wED2t5vTJxxbgogHEmWnfs7p8EP5IsN6Vnjd0VNIt1tu3TduS8kH5npkPqZz8oIP93Ypxn0l7ZNEl9MahbhPj3gJ1YY7Cygrlt1VLC1ibBbOgIS2Lj6vGG/Yjkqs3Vw6qrmTRlsJ9c6bZO2xq0xzV11XQHvjPegBOClF6AztEe1jKU/RUFnzjIF8lUmM63fTaXuVkNERkTSE3E9XL3Uq6eqYdef7wHFFhCMSGotp3ANAb30kflysA9ID0b3o5QU2tB8OBxBicXQy11lh+u204YJuvIzeTXo+JAad5TWFlJcsUlbPFppLQdhUpoWaJouBGJV36DJb9R34i9T8Ze5tnJUQgPmMkERyPvb/+v5j3s2hs1A9WO6/MqmZd70gudsX/1bqWT898vCCOdM+CspNVY7nHVUtde7C6BrHzphr/C1YBXHw==" + +var testAccInstanceBasic = fmt.Sprintf(` +resource "opc_compute_instance" "%s" { + name = "test" + label = "test" + shape = "oc3" + imageList = "/oracle/public/oel_6.4_2GB_v1" + sshKeys = ["${opc_compute_ssh_key.test_key.name}"] + attributes = "{\"foo\": \"bar\"}" + storage = { + index = 1 + volume = "${opc_compute_storage_volume.test_volume.name}" + } +} + +resource "opc_compute_storage_volume" "test_volume" { + size = "3g" + description = "My volume" + name = "test_volume_b" + tags = ["foo", "bar", "baz"] +} + +resource "opc_compute_ssh_key" "%s" { + name = "test-key" + key = "%s" + enabled = true +} +`, instanceName, keyName, originalKey) + +var modifySSHKey = fmt.Sprintf(` +resource "opc_compute_instance" "%s" { + name = "test" + label = "test" + shape = "oc3" + imageList = "/oracle/public/oel_6.4_2GB_v1" + sshKeys = ["${opc_compute_ssh_key.test_key.name}"] + attributes = "{\"foo\": \"bar\"}" + storage = { + index = 1 + volume = "${opc_compute_storage_volume.test_volume.name}" + } +} + +resource "opc_compute_storage_volume" "test_volume" { + size = "3g" + description = "My volume" + name = "test_volume_b" + tags = ["foo", "bar", "baz"] +} + +resource "opc_compute_ssh_key" "%s" { + name = "test-key" + key = "%s" + enabled = true +} +`, instanceName, keyName, updatedKey) diff --git a/builtin/providers/oracleopc/resource_ip_association.go b/builtin/providers/oracleopc/resource_ip_association.go new file mode 100644 index 000000000..84df10ba8 --- /dev/null +++ b/builtin/providers/oracleopc/resource_ip_association.go @@ -0,0 +1,103 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceIPAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceIPAssociationCreate, + Read: resourceIPAssociationRead, + Delete: resourceIPAssociationDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "vcable": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "parentpool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceIPAssociationCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + vcable, parentpool := getIPAssociationResourceData(d) + + log.Printf("[DEBUG] Creating ip association between vcable %s and parent pool %s", + vcable, parentpool) + + client := meta.(*OPCClient).IPAssociations() + info, err := client.CreateIPAssociation(vcable, parentpool) + 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) + updateIPAssociationResourceData(d, info) + return nil +} + +func updateIPAssociationResourceData(d *schema.ResourceData, info *compute.IPAssociationInfo) { + d.Set("name", info.Name) + d.Set("parentpool", info.ParentPool) + d.Set("vcable", info.VCable) +} + +func resourceIPAssociationRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).IPAssociations() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of ip association %s", name) + result, err := client.GetIPAssociation(name) + 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) + } + + log.Printf("[DEBUG] Read state of ip association %s: %#v", name, result) + updateIPAssociationResourceData(d, result) + return nil +} + +func getIPAssociationResourceData(d *schema.ResourceData) (string, string) { + return d.Get("vcable").(string), d.Get("parentpool").(string) +} + +func resourceIPAssociationDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).IPAssociations() + name := d.Get("name").(string) + + vcable, parentpool := getIPAssociationResourceData(d) + log.Printf("[DEBUG] Deleting ip association %s between vcable %s and parent pool %s", + name, vcable, parentpool) + + if err := client.DeleteIPAssociation(name); err != nil { + return fmt.Errorf("Error deleting ip association %s between vcable %s and parent pool %s: %s", + name, vcable, parentpool, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_ip_association_test.go b/builtin/providers/oracleopc/resource_ip_association_test.go new file mode 100644 index 000000000..44f48474f --- /dev/null +++ b/builtin/providers/oracleopc/resource_ip_association_test.go @@ -0,0 +1,74 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccOPCResourceIPAssociation_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: opcResourceCheck( + ipAssociationResourceName, + testAccCheckIPAssociationDestroyed), + Steps: []resource.TestStep{ + { + Config: testAccIPAssociationBasic, + Check: resource.ComposeTestCheckFunc( + opcResourceCheck( + ipAssociationResourceName, + testAccCheckIPAssociationExists), + ), + }, + }, + }) +} + +func testAccCheckIPAssociationExists(state *OPCResourceState) error { + associationName := getIPAssociationName(state) + + if _, err := state.IPAssociations().GetIPAssociation(associationName); err != nil { + return fmt.Errorf("Error retrieving state of ip assocation %s: %s", associationName, err) + } + + return nil +} + +func getIPAssociationName(rs *OPCResourceState) string { + return rs.Attributes["name"] +} + +func testAccCheckIPAssociationDestroyed(state *OPCResourceState) error { + associationName := getAssociationName(state) + if info, err := state.IPAssociations().GetIPAssociation(associationName); err == nil { + return fmt.Errorf("IP association %s still exists: %#v", associationName, info) + } + + return nil +} + +const ipAssociationName = "test_ip_association" + +var ipAssociationResourceName = fmt.Sprintf("opc_compute_ip_association.%s", ipAssociationName) + +var testAccIPAssociationBasic = fmt.Sprintf(` +resource "opc_compute_ip_reservation" "reservation1" { + parentpool = "/oracle/public/ippool" + permanent = true +} + +resource "opc_compute_ip_association" "%s" { + vcable = "${opc_compute_instance.test-instance1.vcable}" + parentpool = "ipreservation:${opc_compute_ip_reservation.reservation1.name}" +} + +resource "opc_compute_instance" "test-instance1" { + name = "test" + label = "test" + shape = "oc3" + imageList = "/oracle/public/oel_6.4_2GB_v1" +} +`, ipAssociationName) diff --git a/builtin/providers/oracleopc/resource_ip_reservation.go b/builtin/providers/oracleopc/resource_ip_reservation.go new file mode 100644 index 000000000..fa25679d2 --- /dev/null +++ b/builtin/providers/oracleopc/resource_ip_reservation.go @@ -0,0 +1,122 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceIPReservation() *schema.Resource { + return &schema.Resource{ + Create: resourceIPReservationCreate, + Read: resourceIPReservationRead, + Delete: resourceIPReservationDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "permanent": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + ForceNew: true, + }, + + "parentpool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "ip": &schema.Schema{ + Type: schema.TypeString, + Optional: false, + Computed: true, + }, + }, + } +} + +func resourceIPReservationCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + parentpool, permanent, tags := getIPReservationResourceData(d) + + log.Printf("[DEBUG] Creating ip reservation from parentpool %s with tags=%s", + parentpool, tags) + + client := meta.(*OPCClient).IPReservations() + info, err := client.CreateIPReservation(parentpool, permanent, tags) + if err != nil { + return fmt.Errorf("Error creating ip reservation from parentpool %s with tags=%s: %s", + parentpool, tags, err) + } + + d.SetId(info.Name) + updateIPReservationResourceData(d, info) + return nil +} + +func updateIPReservationResourceData(d *schema.ResourceData, info *compute.IPReservationInfo) { + d.Set("name", info.Name) + d.Set("parentpool", info.ParentPool) + d.Set("permanent", info.Permanent) + d.Set("tags", info.Tags) + d.Set("ip", info.IP) +} + +func resourceIPReservationRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).IPReservations() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of ip reservation %s", name) + result, err := client.GetIPReservation(name) + if err != nil { + // IP Reservation does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading ip reservation %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of ip reservation %s: %#v", name, result) + updateIPReservationResourceData(d, result) + return nil +} + +func getIPReservationResourceData(d *schema.ResourceData) (string, bool, []string) { + tagdata := d.Get("tags").([]interface{}) + tags := make([]string, len(tagdata)) + for i, tag := range tagdata { + tags[i] = tag.(string) + } + return d.Get("parentpool").(string), + d.Get("permanent").(bool), + tags +} + +func resourceIPReservationDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).IPReservations() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting ip reservation %s", name) + + if err := client.DeleteIPReservation(name); err != nil { + return fmt.Errorf("Error deleting ip reservation %s", name) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_security_application.go b/builtin/providers/oracleopc/resource_security_application.go new file mode 100644 index 000000000..b7205754c --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_application.go @@ -0,0 +1,124 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceSecurityApplication() *schema.Resource { + return &schema.Resource{ + Create: resourceSecurityApplicationCreate, + Read: resourceSecurityApplicationRead, + Delete: resourceSecurityApplicationDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "dport": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "icmptype": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "icmpcode": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceSecurityApplicationCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + name, protocol, dport, icmptype, icmpcode, description := getSecurityApplicationResourceData(d) + + log.Printf("[DEBUG] Creating security application %s", name) + + client := meta.(*OPCClient).SecurityApplications() + info, err := client.CreateSecurityApplication(name, protocol, dport, icmptype, icmpcode, description) + if err != nil { + return fmt.Errorf("Error creating security application %s: %s", name, err) + } + + d.SetId(info.Name) + updateSecurityApplicationResourceData(d, info) + return nil +} + +func updateSecurityApplicationResourceData(d *schema.ResourceData, info *compute.SecurityApplicationInfo) { + d.Set("name", info.Name) + d.Set("protocol", info.Protocol) + d.Set("dport", info.DPort) + d.Set("icmptype", info.ICMPType) + d.Set("icmpcode", info.ICMPCode) + d.Set("description", info.Description) +} + +func resourceSecurityApplicationRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityApplications() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of security application %s", name) + result, err := client.GetSecurityApplication(name) + if err != nil { + // Security Application does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading security application %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of security application %s: %#v", name, result) + updateSecurityApplicationResourceData(d, result) + return nil +} + +func getSecurityApplicationResourceData(d *schema.ResourceData) (string, string, string, string, string, string) { + return d.Get("name").(string), + d.Get("protocol").(string), + d.Get("dport").(string), + d.Get("icmptype").(string), + d.Get("icmpcode").(string), + d.Get("description").(string) +} + +func resourceSecurityApplicationDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityApplications() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting security application %s", name) + + if err := client.DeleteSecurityApplication(name); err != nil { + return fmt.Errorf("Error deleting security application %s: %s", name, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_security_association.go b/builtin/providers/oracleopc/resource_security_association.go new file mode 100644 index 000000000..15a912657 --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_association.go @@ -0,0 +1,103 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceSecurityAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceSecurityAssociationCreate, + Read: resourceSecurityAssociationRead, + Delete: resourceSecurityAssociationDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "vcable": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "seclist": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceSecurityAssociationCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + vcable, seclist := getSecurityAssociationResourceData(d) + + log.Printf("[DEBUG] Creating security association between vcable %s and security list %s", + vcable, seclist) + + client := meta.(*OPCClient).SecurityAssociations() + info, err := client.CreateSecurityAssociation(vcable, seclist) + if err != nil { + return fmt.Errorf("Error creating security association between vcable %s and security list %s: %s", + vcable, seclist, err) + } + + d.SetId(info.Name) + updateSecurityAssociationResourceData(d, info) + return nil +} + +func updateSecurityAssociationResourceData(d *schema.ResourceData, info *compute.SecurityAssociationInfo) { + d.Set("name", info.Name) + d.Set("seclist", info.SecList) + d.Set("vcable", info.VCable) +} + +func resourceSecurityAssociationRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityAssociations() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of security association %s", name) + result, err := client.GetSecurityAssociation(name) + if err != nil { + // Security Association does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading security association %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of security association %s: %#v", name, result) + updateSecurityAssociationResourceData(d, result) + return nil +} + +func getSecurityAssociationResourceData(d *schema.ResourceData) (string, string) { + return d.Get("vcable").(string), d.Get("seclist").(string) +} + +func resourceSecurityAssociationDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityAssociations() + name := d.Get("name").(string) + + vcable, seclist := getSecurityAssociationResourceData(d) + log.Printf("[DEBUG] Deleting security association %s between vcable %s and security list %s", + name, vcable, seclist) + + if err := client.DeleteSecurityAssociation(name); err != nil { + return fmt.Errorf("Error deleting security association %s between vcable %s and security list %s: %s", + name, vcable, seclist, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_security_association_test.go b/builtin/providers/oracleopc/resource_security_association_test.go new file mode 100644 index 000000000..604ef64cb --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_association_test.go @@ -0,0 +1,75 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccOPCResourceSecurityAssociation_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: opcResourceCheck( + associationResourceName, + testAccCheckAssociationDestroyed), + Steps: []resource.TestStep{ + { + Config: testAccSecurityAssociationBasic, + Check: resource.ComposeTestCheckFunc( + opcResourceCheck( + associationResourceName, + testAccCheckAssociationExists), + ), + }, + }, + }) +} + +func testAccCheckAssociationExists(state *OPCResourceState) error { + associationName := getAssociationName(state) + + if _, err := state.SecurityAssociations().GetSecurityAssociation(associationName); err != nil { + return fmt.Errorf("Error retrieving state of security assocation %s: %s", associationName, err) + } + + return nil +} + +func getAssociationName(rs *OPCResourceState) string { + return rs.Attributes["name"] +} + +func testAccCheckAssociationDestroyed(state *OPCResourceState) error { + associationName := getAssociationName(state) + if info, err := state.SecurityAssociations().GetSecurityAssociation(associationName); err == nil { + return fmt.Errorf("Association %s still exists: %#v", associationName, info) + } + + return nil +} + +const associationName = "test_rule" + +var associationResourceName = fmt.Sprintf("opc_compute_security_association.%s", associationName) + +var testAccSecurityAssociationBasic = fmt.Sprintf(` +resource "opc_compute_security_list" "sec-list1" { + name = "sec-list-1" + policy = "PERMIT" + outbound_cidr_policy = "DENY" +} + +resource "opc_compute_security_association" "%s" { + vcable = "${opc_compute_instance.test-instance1.vcable}" + seclist = "${opc_compute_security_list.sec-list1.name}" +} + +resource "opc_compute_instance" "test-instance1" { + name = "test" + label = "test" + shape = "oc3" + imageList = "/oracle/public/oel_6.4_2GB_v1" +} +`, ruleName) diff --git a/builtin/providers/oracleopc/resource_security_ip_list.go b/builtin/providers/oracleopc/resource_security_ip_list.go new file mode 100644 index 000000000..6a3e66b28 --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_ip_list.go @@ -0,0 +1,117 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceSecurityIPList() *schema.Resource { + return &schema.Resource{ + Create: resourceSecurityIPListCreate, + Read: resourceSecurityIPListRead, + Update: resourceSecurityIPListUpdate, + Delete: resourceSecurityIPListDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "ip_entries": &schema.Schema{ + Type: schema.TypeList, + Required: true, + ForceNew: false, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceSecurityIPListCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + name, ipEntries := getSecurityIPListResourceData(d) + + log.Printf("[DEBUG] Creating security IP list with name %s, entries %s", + name, ipEntries) + + client := meta.(*OPCClient).SecurityIPLists() + info, err := client.CreateSecurityIPList(name, ipEntries) + if err != nil { + return fmt.Errorf("Error creating security IP list %s: %s", name, err) + } + + d.SetId(info.Name) + updateSecurityIPListResourceData(d, info) + return nil +} + +func updateSecurityIPListResourceData(d *schema.ResourceData, info *compute.SecurityIPListInfo) { + d.Set("name", info.Name) + d.Set("entries", info.SecIPEntries) +} + +func resourceSecurityIPListRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityIPLists() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of security IP list %s", name) + result, err := client.GetSecurityIPList(name) + if err != nil { + // Security IP List does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading security IP list %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of security IP list %s: %#v", name, result) + updateSecurityIPListResourceData(d, result) + return nil +} + +func getSecurityIPListResourceData(d *schema.ResourceData) (string, []string) { + name := d.Get("name").(string) + ipEntries := d.Get("ip_entries").([]interface{}) + ipEntryStrings := []string{} + for _, entry := range ipEntries { + ipEntryStrings = append(ipEntryStrings, entry.(string)) + } + return name, ipEntryStrings +} + +func resourceSecurityIPListUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + client := meta.(*OPCClient).SecurityIPLists() + name, entries := getSecurityIPListResourceData(d) + + log.Printf("[DEBUG] Updating security IP list %s with ip entries %s", + name, entries) + + info, err := client.UpdateSecurityIPList(name, entries) + if err != nil { + return fmt.Errorf("Error updating security IP list %s: %s", name, err) + } + + updateSecurityIPListResourceData(d, info) + return nil +} + +func resourceSecurityIPListDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityIPLists() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting security IP list %s", name) + if err := client.DeleteSecurityIPList(name); err != nil { + return fmt.Errorf("Error deleting security IP list %s: %s", name, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_security_list.go b/builtin/providers/oracleopc/resource_security_list.go new file mode 100644 index 000000000..eea11bbb1 --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_list.go @@ -0,0 +1,119 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceSecurityList() *schema.Resource { + return &schema.Resource{ + Create: resourceSecurityListCreate, + Read: resourceSecurityListRead, + Update: resourceSecurityListUpdate, + Delete: resourceSecurityListDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "outbound_cidr_policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + }, + } +} + +func resourceSecurityListCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + name, policy, outboundCIDRPolicy := getSecurityListResourceData(d) + + log.Printf("[DEBUG] Creating security list with name %s, policy %s, outbound CIDR policy %s", + name, policy, outboundCIDRPolicy) + + client := meta.(*OPCClient).SecurityLists() + info, err := client.CreateSecurityList(name, policy, outboundCIDRPolicy) + if err != nil { + return fmt.Errorf("Error creating security list %s: %s", name, err) + } + + d.SetId(info.Name) + updateSecurityListResourceData(d, info) + return nil +} + +func updateSecurityListResourceData(d *schema.ResourceData, info *compute.SecurityListInfo) { + d.Set("name", info.Name) + d.Set("policy", info.Policy) + d.Set("outbound_cidr_policy", info.OutboundCIDRPolicy) +} + +func resourceSecurityListRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityLists() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of security list %s", name) + result, err := client.GetSecurityList(name) + if err != nil { + // Security List does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading security list %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of ssh key %s: %#v", name, result) + updateSecurityListResourceData(d, result) + return nil +} + +func getSecurityListResourceData(d *schema.ResourceData) (string, string, string) { + return d.Get("name").(string), + d.Get("policy").(string), + d.Get("outbound_cidr_policy").(string) +} + +func resourceSecurityListUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + client := meta.(*OPCClient).SecurityLists() + name, policy, outboundCIDRPolicy := getSecurityListResourceData(d) + + log.Printf("[DEBUG] Updating security list %s with policy %s, outbound_cidr_policy %s", + name, policy, outboundCIDRPolicy) + + info, err := client.UpdateSecurityList(name, policy, outboundCIDRPolicy) + if err != nil { + return fmt.Errorf("Error updating security list %s: %s", name, err) + } + + updateSecurityListResourceData(d, info) + return nil +} + +func resourceSecurityListDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityLists() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting ssh key volume %s", name) + if err := client.DeleteSecurityList(name); err != nil { + return fmt.Errorf("Error deleting security list %s: %s", name, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_security_rule.go b/builtin/providers/oracleopc/resource_security_rule.go new file mode 100644 index 000000000..0d9eb562c --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_rule.go @@ -0,0 +1,143 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceSecurityRule() *schema.Resource { + return &schema.Resource{ + Create: resourceSecurityRuleCreate, + Read: resourceSecurityRuleRead, + Update: resourceSecurityRuleUpdate, + Delete: resourceSecurityRuleDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "source_list": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "destination_list": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "application": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "action": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "disabled": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + ForceNew: false, + }, + }, + } +} + +func resourceSecurityRuleCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + name, sourceList, destinationList, application, action, disabled := getSecurityRuleResourceData(d) + + log.Printf("[DEBUG] Creating security list with name %s, sourceList %s, destinationList %s, application %s, action %s, disabled %s", + name, sourceList, destinationList, application, action, disabled) + + client := meta.(*OPCClient).SecurityRules() + info, err := client.CreateSecurityRule(name, sourceList, destinationList, application, action, disabled) + if err != nil { + return fmt.Errorf("Error creating security rule %s: %s", name, err) + } + + d.SetId(info.Name) + updateSecurityRuleResourceData(d, info) + return nil +} + +func updateSecurityRuleResourceData(d *schema.ResourceData, info *compute.SecurityRuleInfo) { + d.Set("name", info.Name) + d.Set("source_list", info.SourceList) + d.Set("destination_list", info.DestinationList) + d.Set("application", info.Application) + d.Set("action", info.Action) + d.Set("disabled", info.Disabled) +} + +func resourceSecurityRuleRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityRules() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of security rule %s", name) + result, err := client.GetSecurityRule(name) + if err != nil { + // Security Rule does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading security list %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of ssh key %s: %#v", name, result) + updateSecurityRuleResourceData(d, result) + return nil +} + +func getSecurityRuleResourceData(d *schema.ResourceData) (string, string, string, string, string, bool) { + return d.Get("name").(string), + d.Get("source_list").(string), + d.Get("destination_list").(string), + d.Get("application").(string), + d.Get("action").(string), + d.Get("disabled").(bool) +} + +func resourceSecurityRuleUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + + client := meta.(*OPCClient).SecurityRules() + name, sourceList, destinationList, application, action, disabled := getSecurityRuleResourceData(d) + + log.Printf("[DEBUG] Updating security list %s with sourceList %s, destinationList %s, application %s, action %s, disabled %s", + name, sourceList, destinationList, application, action, disabled) + + info, err := client.UpdateSecurityRule(name, sourceList, destinationList, application, action, disabled) + if err != nil { + return fmt.Errorf("Error updating security rule %s: %s", name, err) + } + + updateSecurityRuleResourceData(d, info) + return nil +} + +func resourceSecurityRuleDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource state: %#v", d.State()) + client := meta.(*OPCClient).SecurityRules() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting ssh key volume %s", name) + if err := client.DeleteSecurityRule(name); err != nil { + return fmt.Errorf("Error deleting security rule %s: %s", name, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_security_rule_test.go b/builtin/providers/oracleopc/resource_security_rule_test.go new file mode 100644 index 000000000..f09c2b879 --- /dev/null +++ b/builtin/providers/oracleopc/resource_security_rule_test.go @@ -0,0 +1,85 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccOPCResourceSecurityRule_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: opcResourceCheck( + ruleResourceName, + testAccCheckRuleDestroyed), + Steps: []resource.TestStep{ + { + Config: testAccSecurityRuleBasic, + Check: resource.ComposeTestCheckFunc( + opcResourceCheck( + ruleResourceName, + testAccCheckRuleExists), + ), + }, + }, + }) +} + +func testAccCheckRuleExists(state *OPCResourceState) error { + ruleName := getRuleName(state) + + if _, err := state.SecurityRules().GetSecurityRule(ruleName); err != nil { + return fmt.Errorf("Error retrieving state of security rule %s: %s", ruleName, err) + } + + return nil +} + +func getRuleName(rs *OPCResourceState) string { + return rs.Attributes["name"] +} + +func testAccCheckRuleDestroyed(state *OPCResourceState) error { + ruleName := getRuleName(state) + if info, err := state.SecurityRules().GetSecurityRule(ruleName); err == nil { + return fmt.Errorf("Rule %s still exists: %#v", ruleName, info) + } + + return nil +} + +const ruleName = "test_rule" +const secListName = "sec-list1" +const secIpListName = "sec-ip-list1" + +var ruleResourceName = fmt.Sprintf("opc_compute_security_rule.%s", ruleName) + +var testAccSecurityRuleBasic = fmt.Sprintf(` +resource "opc_compute_security_rule" "%s" { + name = "test" + source_list = "seclist:${opc_compute_security_list.sec-list1.name}" + destination_list = "seciplist:${opc_compute_security_ip_list.sec-ip-list1.name}" + action = "PERMIT" + application = "${opc_compute_security_application.spring-boot.name}" + disabled = false +} + +resource "opc_compute_security_list" "%s" { + name = "sec-list-1" + policy = "PERMIT" + outbound_cidr_policy = "DENY" +} + +resource "opc_compute_security_application" "spring-boot" { + name = "spring-boot" + protocol = "tcp" + dport = "8080" +} + +resource "opc_compute_security_ip_list" "%s" { + name = "sec-ip-list1" + ip_entries = ["217.138.34.4"] +} +`, ruleName, secListName, secIpListName) diff --git a/builtin/providers/oracleopc/resource_ssh_key.go b/builtin/providers/oracleopc/resource_ssh_key.go new file mode 100644 index 000000000..29f68b4aa --- /dev/null +++ b/builtin/providers/oracleopc/resource_ssh_key.go @@ -0,0 +1,117 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceSSHKey() *schema.Resource { + return &schema.Resource{ + Create: resourceSSHKeyCreate, + Read: resourceSSHKeyRead, + Update: resourceSSHKeyUpdate, + Delete: resourceSSHKeyDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "key": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + ForceNew: false, + }, + }, + } +} + +func resourceSSHKeyCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d) + + client := meta.(*OPCClient).SSHKeys() + name := d.Get("name").(string) + key := d.Get("key").(string) + enabled := d.Get("enabled").(bool) + + log.Printf("[DEBUG] Creating ssh key with name %s, key %s, enabled %s", + name, key, enabled) + + info, err := client.CreateSSHKey(name, key, enabled) + if err != nil { + return fmt.Errorf("Error creating ssh key %s: %s", name, err) + } + + d.SetId(info.Name) + updateSSHKeyResourceData(d, info) + return nil +} + +func updateSSHKeyResourceData(d *schema.ResourceData, info *compute.SSHKeyInfo) { + d.Set("name", info.Name) + d.Set("key", info.Key) + d.Set("enabled", info.Enabled) +} + +func resourceSSHKeyRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d) + client := meta.(*OPCClient).SSHKeys() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of ssh key %s", name) + result, err := client.GetSSHKey(name) + if err != nil { + // SSH Key does not exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading ssh key %s: %s", name, err) + } + + log.Printf("[DEBUG] Read state of ssh key %s: %#v", name, result) + updateSSHKeyResourceData(d, result) + return nil +} + +func resourceSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d) + + client := meta.(*OPCClient).SSHKeys() + name := d.Get("name").(string) + key := d.Get("key").(string) + enabled := d.Get("enabled").(bool) + + log.Printf("[DEBUG] Updating ssh key with name %s, key %s, enabled %s", + name, key, enabled) + + info, err := client.UpdateSSHKey(name, key, enabled) + if err != nil { + return fmt.Errorf("Error updating ssh key %s: %s", name, err) + } + + updateSSHKeyResourceData(d, info) + return nil +} + +func resourceSSHKeyDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d) + client := meta.(*OPCClient).SSHKeys() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting ssh key volume %s", name) + if err := client.DeleteSSHKey(name); err != nil { + return fmt.Errorf("Error deleting ssh key %s: %s", name, err) + } + return nil +} diff --git a/builtin/providers/oracleopc/resource_storage_volume.go b/builtin/providers/oracleopc/resource_storage_volume.go new file mode 100644 index 000000000..2d80d09f2 --- /dev/null +++ b/builtin/providers/oracleopc/resource_storage_volume.go @@ -0,0 +1,301 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "github.com/oracle/terraform-provider-compute/sdk/compute" + "log" +) + +func resourceStorageVolume() *schema.Resource { + return &schema.Resource{ + Create: resourceStorageVolumeCreate, + Read: resourceStorageVolumeRead, + Update: resourceStorageVolumeUpdate, + Delete: resourceStorageVolumeDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "size": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "sizeInBytes": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "storage": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "/oracle/public/storage/default", + }, + + "tags": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: false, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "bootableImage": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "bootableImageVersion": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Default: -1, + }, + + "snapshot": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "account": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + + "snapshotId": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceStorageVolumeCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Resource data: %#v", d) + + sv := meta.(*OPCClient).StorageVolumes() + name := d.Get("name").(string) + properties := []string{d.Get("storage").(string)} + + spec := sv.NewStorageVolumeSpec( + d.Get("size").(string), + properties, + name) + + if d.Get("description").(string) != "" { + spec.SetDescription(d.Get("description").(string)) + } + + spec.SetTags(getTags(d)) + + if d.Get("bootableImage") != "" { + spec.SetBootableImage(d.Get("bootableImage").(string), d.Get("bootableImageVersion").(int)) + } + + if len(d.Get("snapshot").(*schema.Set).List()) > 0 { + snapshotDetails := d.Get("snapshot").(*schema.Set).List()[0].(map[string]interface{}) + spec.SetSnapshot( + snapshotDetails["name"].(string), + snapshotDetails["account"].(string), + ) + } + + if d.Get("snapshotId") != "" { + spec.SetSnapshotID(d.Get("snapshotId").(string)) + } + + log.Printf("[DEBUG] Creating storage volume %s with spec %#v", name, spec) + err := sv.CreateStorageVolume(spec) + if err != nil { + return fmt.Errorf("Error creating storage volume %s: %s", name, err) + } + + log.Printf("[DEBUG] Waiting for storage volume %s to come online", name) + info, err := sv.WaitForStorageVolumeOnline(name, meta.(*OPCClient).MaxRetryTimeout) + if err != nil { + return fmt.Errorf("Error waiting for storage volume %s to come online: %s", name, err) + } + + log.Printf("[DEBUG] Created storage volume %s: %#v", name, info) + + cachedAttachments, attachmentsFound := meta.(*OPCClient).storageAttachmentsByVolumeCache[name] + if attachmentsFound { + log.Printf("[DEBUG] Rebuilding storage attachments for volume %s", name) + for _, cachedAttachment := range cachedAttachments { + log.Printf("[DEBUG] Rebuilding storage attachments between volume %s and instance %s", + name, + cachedAttachment.instanceName) + + attachmentInfo, err := meta.(*OPCClient).StorageAttachments().CreateStorageAttachment( + cachedAttachment.index, + cachedAttachment.instanceName, + name, + ) + + if err != nil { + return fmt.Errorf( + "Error recreating storage attachment between volume %s and instance %s: %s", + name, + *cachedAttachment.instanceName, + err) + } + err = meta.(*OPCClient).StorageAttachments().WaitForStorageAttachmentCreated( + attachmentInfo.Name, + meta.(*OPCClient).MaxRetryTimeout) + if err != nil { + return fmt.Errorf( + "Error recreating storage attachment between volume %s and instance %s: %s", + name, + *cachedAttachment.instanceName, + err) + } + } + meta.(*OPCClient).storageAttachmentsByVolumeCache[name] = nil + } + + d.SetId(name) + updateResourceData(d, info) + return nil +} + +func getTags(d *schema.ResourceData) []string { + tags := []string{} + for _, i := range d.Get("tags").([]interface{}) { + tags = append(tags, i.(string)) + } + return tags +} + +func updateResourceData(d *schema.ResourceData, info *compute.StorageVolumeInfo) error { + d.Set("name", info.Name) + d.Set("description", info.Description) + d.Set("storage", info.Properties[0]) + d.Set("sizeInBytes", info.Size) + d.Set("tags", info.Tags) + d.Set("bootableImage", info.ImageList) + d.Set("bootableImageVersion", info.ImageListEntry) + if info.Snapshot != "" { + d.Set("snapshot", map[string]interface{}{ + "name": info.Snapshot, + "account": info.SnapshotAccount, + }) + } + d.Set("snapshotId", info.SnapshotID) + + return nil +} + +func resourceStorageVolumeRead(d *schema.ResourceData, meta interface{}) error { + sv := meta.(*OPCClient).StorageVolumes() + name := d.Get("name").(string) + + log.Printf("[DEBUG] Reading state of storage volume %s", name) + result, err := sv.GetStorageVolume(name) + if err != nil { + // Volume doesn't exist + if compute.WasNotFoundError(err) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading storage volume %s: %s", name, err) + } + + if len(result.Result) == 0 { + // Volume doesn't exist + d.SetId("") + return nil + } + + log.Printf("[DEBUG] Read state of storage volume %s: %#v", name, &result.Result[0]) + updateResourceData(d, &result.Result[0]) + + return nil +} + +func resourceStorageVolumeUpdate(d *schema.ResourceData, meta interface{}) error { + sv := meta.(*OPCClient).StorageVolumes() + name := d.Get("name").(string) + description := d.Get("description").(string) + size := d.Get("size").(string) + tags := getTags(d) + + log.Printf("[DEBUG] Updating storage volume %s with size %s, description %s, tags %#v", name, size, description, tags) + err := sv.UpdateStorageVolume(name, size, description, tags) + + if err != nil { + return fmt.Errorf("Error updating storage volume %s: %s", name, err) + } + + log.Printf("[DEBUG] Waiting for updated storage volume %s to come online", name) + info, err := sv.WaitForStorageVolumeOnline(name, meta.(*OPCClient).MaxRetryTimeout) + if err != nil { + return fmt.Errorf("Error waiting for updated storage volume %s to come online: %s", name, err) + } + + log.Printf("[DEBUG] Updated storage volume %s: %#v", name, info) + updateResourceData(d, info) + return nil +} + +func resourceStorageVolumeDelete(d *schema.ResourceData, meta interface{}) error { + sv := meta.(*OPCClient).StorageVolumes() + name := d.Get("name").(string) + + sva := meta.(*OPCClient).StorageAttachments() + attachments, err := sva.GetStorageAttachmentsForVolume(name) + if err != nil { + return fmt.Errorf("Error retrieving storage attachments for volume %s: %s", name, err) + } + + attachmentsToCache := make([]storageAttachment, len(*attachments)) + for index, attachment := range *attachments { + log.Printf("[DEBUG] Deleting storage attachment %s for volume %s", attachment.Name, name) + sva.DeleteStorageAttachment(attachment.Name) + sva.WaitForStorageAttachmentDeleted(attachment.Name, meta.(*OPCClient).MaxRetryTimeout) + attachmentsToCache[index] = storageAttachment{ + index: attachment.Index, + instanceName: compute.InstanceNameFromString(attachment.InstanceName), + } + } + meta.(*OPCClient).storageAttachmentsByVolumeCache[name] = attachmentsToCache + + log.Printf("[DEBUG] Deleting storage volume %s", name) + err = sv.DeleteStorageVolume(name) + if err != nil { + return fmt.Errorf("Error deleting storage volume %s: %s", name, err) + } + + log.Printf("[DEBUG] Waiting for storage volume %s to finish deleting", name) + err = sv.WaitForStorageVolumeDeleted(name, meta.(*OPCClient).MaxRetryTimeout) + if err != nil { + return fmt.Errorf("Error waiting for storage volume %s to finish deleting: %s", name, err) + } + + log.Printf("[DEBUG] Deleted storage volume %s", name) + return nil +} diff --git a/builtin/providers/oracleopc/resource_storage_volume_test.go b/builtin/providers/oracleopc/resource_storage_volume_test.go new file mode 100644 index 000000000..d168b5309 --- /dev/null +++ b/builtin/providers/oracleopc/resource_storage_volume_test.go @@ -0,0 +1,70 @@ +package opc + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccOPCStorageVolume_Basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: opcResourceCheck( + "opc_compute_storage_volume.test_volume", + testAccCheckStorageVolumeDestroyed), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccStorageVolumeBasic, + Check: resource.ComposeTestCheckFunc( + opcResourceCheck( + "opc_compute_storage_volume.test_volume", + testAccCheckStorageVolumeExists), + ), + }, + }, + }) +} + +func testAccCheckStorageVolumeExists(state *OPCResourceState) error { + sv := state.StorageVolumes() + volumeName := state.Attributes["name"] + + info, err := sv.GetStorageVolume(volumeName) + if err != nil { + return fmt.Errorf("Error retrieving state of volume %s: %s", volumeName, err) + } + + if len(info.Result) == 0 { + return fmt.Errorf("No info found for volume %s", volumeName) + } + + return nil +} + +func testAccCheckStorageVolumeDestroyed(state *OPCResourceState) error { + sv := state.StorageVolumes() + + volumeName := state.Attributes["name"] + + info, err := sv.GetStorageVolume(volumeName) + if err != nil { + return fmt.Errorf("Error retrieving state of volume %s: %s", volumeName, err) + } + + if len(info.Result) != 0 { + return fmt.Errorf("Volume %s still exists", volumeName) + } + + return nil +} + +const testAccStorageVolumeBasic = ` +resource "opc_compute_storage_volume" "test_volume" { + size = "3g" + description = "My volume" + name = "test_volume_b" + tags = ["foo", "bar", "baz"] +} +` diff --git a/website/source/docs/providers/oracleopc/d/opc_compute_vnic.html.markdown b/website/source/docs/providers/oracleopc/d/opc_compute_vnic.html.markdown new file mode 100644 index 000000000..78be49c4a --- /dev/null +++ b/website/source/docs/providers/oracleopc/d/opc_compute_vnic.html.markdown @@ -0,0 +1,36 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_vnic" +sidebar_current: "docs-oracleopc-datasource-vnic" +description: |- + Gets information about the configuration of a Virtual NIC. +--- + +# opc\_compute\_vnic + +Use this data source to access the configuration of a Virtual NIC. + +## Example Usage + +``` +data "opc_compute_vnic" "current" {} + +output "mac_address" { + value = "${data.opc_compute_vnic.current.mac_address}" +} +``` + +## Argument Reference +* `name` is the name of the Virtual NIC. + +## Attributes Reference + +* `description` is a description of the Virtual NIC. + +* `mac_address` is the MAC Address of the Virtual NIC. + +* `tags` is a list of Tags associated with the Virtual NIC. + +* `transit_flag` is `true` if the Virtual NIC is of the type `transit`. + +* `uri` is the Unique Resource Locator of the Virtual NIC. diff --git a/website/source/docs/providers/oracleopc/index.html.markdown b/website/source/docs/providers/oracleopc/index.html.markdown new file mode 100644 index 000000000..598346919 --- /dev/null +++ b/website/source/docs/providers/oracleopc/index.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "oracleopc" +page_title: "Provider: Oracle Public Cloud" +sidebar_current: "docs-oracleopc-index" +description: |- + The Oracle Public Cloud provider is used to interact with the many resources supported by the Oracle Public Cloud. The provider needs to be configured with credentials for the Oracle Public Cloud API. +--- + +# Oracle Public Cloud Provider + +The Oracle Public Cloud provider is used to interact with the many resources supported by the Oracle Public Cloud. The provider needs to be configured with credentials for the Oracle Public Cloud API. + +Use the navigation to the left to read about the available resources. + +## Example Usage + +``` +# Configure the Oracle Public Cloud +provider "oracle" { + user = "..." + password = "..." + identity_domain = "..." + endpoint = "..." +} + +# Create an IP Reservation +resource "opc_compute_ip_reservation" "production" { + parent_pool = "/oracle/public/ippool" + permanent = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `user` - (Optional) The username to use, generally your email address. It can also + be sourced from the `OPC_USERNAME` environment variable. + +* `password` - (Optional) The password associated with the username to use. It can also be sourced from + the `OPC_PASSWORD` environment variable. + +* `identity_domain` - (Optional) The identity domain to use. It can also be sourced from + the `OPC_IDENTITY_DOMAIN` environment variable. + +* `endpoint` - (Optional) The API endpoint to use, associated with your Oracle Public Cloud account. This is known as the `REST Endpoint` within the Oracle portal. It can also be sourced from the `OPC_ENDPOINT` environment variable. + +Max num seconds to wait for successful response when operating on resources within OPC (defaults to 3000) +* `max_retry_timeout` - (Optional) The maximum number of seconds to wait for a successful response when operating on resources within Oracle Public Cloud. It can also be sourced from the `OPC_MAX_RETRY_TIMEOUT` environment variable. Defaults to 3000 seconds. + +## Testing + +Credentials must be provided via the `OPC_USERNAME`, `OPC_PASSWORD`, +`OPC_IDENTITY_DOMAIN` and `OPC_ENDPOINT` environment variables in order to run +acceptance tests. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_instance.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_instance.html.markdown new file mode 100644 index 000000000..faeb3ee7c --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_instance.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_instance" +sidebar_current: "docs-oracleopc-resource-instance" +description: |- + Creates and manages an instance in an OPC identity domain. +--- + +# opc\_compute\_instance + +The ``opc_compute_instance`` resource creates and manages an instance in an OPC identity domain. + +~> **Caution:** The ``opc_compute_instance`` resource can completely delete your +instance just as easily as it can create it. To avoid costly accidents, +consider setting +[``prevent_destroy``](/docs/configuration/resources.html#prevent_destroy) +on your instance resources as an extra safety measure. + +## Example Usage + +``` +resource "opc_compute_instance" "test_instance" { + name = "test" + label = "test" + shape = "oc3" + imageList = "/oracle/public/oel_6.4_2GB_v1" + sshKeys = ["${opc_compute_ssh_key.key1.name}"] + attributes = "{\"foo\":\"bar\"}" + storage = [{ + index = 1 + volume = "${opc_compute_storage_volume.test_volume.name}" + }, + { + index = 2 + volume = "${opc_compute_storage_volume.test_volume2.name}" + }] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the instance. This need not be unique, as each instance is assigned a separate +computed `opcId`. + +* `shape` - (Required) The shape of the instance, e.g. `oc4`. + +* `imageList` - (Optional) The imageList of the instance, e.g. `/oracle/public/oel_6.4_2GB_v1` + +* `label` - (Optional) The label to apply to the instance. + +* `ip` - (Computed) The internal IP address assigned to the instance. + +* `opcId` - (Computed) The interned ID assigned to the instance. + +* `sshKeys` - (Optional) The names of the SSH Keys that can be used to log into the instance. + +* `attributes` - (Optional) An arbitrary JSON-formatted collection of attributes which is made available to the instance. + +* `vcable` - (Computed) The ID of the instance's VCable, which is used to associate it with reserved IP addresses and +add it to Security Lists. + +* `storage` - (Optional) A set of zero or more storage volumes to attach to the instance. Each volume has two arguments: +`index`, which is the volume's index in the instance's list of mounted volumes, and `name`, which is the name of the +storage volume to mount. + +* `bootOrder` - (Optional) The index number of the bootable storage volume that should be used to boot the instance. e.g. `[ 1 ]`. If you specify both `bootOrder` and `imageList`, the imagelist attribute is ignored. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_ip_association.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_ip_association.html.markdown new file mode 100644 index 000000000..2518b2df1 --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_ip_association.html.markdown @@ -0,0 +1,31 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_ip_association" +sidebar_current: "docs-oracleopc-resource-ip-association" +description: |- + Creates and manages an IP association in an OPC identity domain. +--- + +# opc\_compute\_ip\_association + +The ``opc_compute_ip_association`` resource creates and manages an association between an IP address and an instance in +an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_ip_association" "instance1_reservation1" { + vcable = "${opc_compute_instance.test_instance.vcable}" + parentpool = "ipreservation:${opc_compute_ip_reservation.reservation1.name}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `vcable` - (Required) The vcable of the instance to associate the IP address with. + +* `parentpool` - (Required) The pool from which to take an IP address. To associate a specific reserved IP address, use +the prefix `ipreservation:` followed by the name of the IP reservation. To allocate an IP address from a pool, use the +prefix `ippool:`, e.g. `ippool:/oracle/public/ippool`. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_ip_reservation.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_ip_reservation.html.markdown new file mode 100644 index 000000000..44b70cc0f --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_ip_reservation.html.markdown @@ -0,0 +1,33 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_ip_reservation" +sidebar_current: "docs-oracleopc-resource-ip-reservation" +description: |- + Creates and manages an IP reservation in an OPC identity domain. +--- + +# opc\_compute\_ip\_reservation + +The ``opc_compute_ip_reservation`` resource creates and manages an IP reservation in an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_ip_reservation" "reservation1" { + parentpool = "/oracle/public/ippool" + permanent = true + tags = [] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `parentpool` - (Required) The pool from which to allocate the IP address. + +* `permanent` - (Required) Whether the IP address remains reserved even when it is no longer associated with an instance +(if true), or may be returned to the pool and replaced with a different IP address when an instance is restarted, or +deleted and recreated (if false). + +* `tags` - (Optional) List of tags that may be applied to the IP reservation. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_security_application.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_security_application.html.markdown new file mode 100644 index 000000000..94760f082 --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_security_application.html.markdown @@ -0,0 +1,39 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_security_application" +sidebar_current: "docs-oracleopc-resource-security-application" +description: |- + Creates and manages a security application in an OPC identity domain. +--- + +# opc\_compute\_security\_application + +The ``opc_compute_security_application`` resource creates and manages a security application in an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_security_application" "tomcat" { + name = "tomcat" + protocol = "tcp" + dport = "8080" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The unique (within the identity domain) name of the application + +* `protocol` - (Required) The protocol to enable for this application. Must be either one of +`tcp`, `udp`, `icmp`, `igmp`, `ipip`, `rdp`, `esp`, `ah`, `gre`, `icmpv6`, `ospf`, `pim`, `sctp`, `mplsip` or `all`, or +the corresponding integer in the range 0-254 from the list of [assigned protocol numbers](http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) + +* `dport` - (Required) The port, or range of ports, to enable for this application, e.g `8080`, `6000-7000`. + +* `icmptype` - (Optional) The ICMP type to enable for this application, if the `protocol` is `icmp`. Must be one of +`echo`, `reply`, `ttl`, `traceroute`, `unreachable`. + +* `icmpcode` - (Optional) The ICMP code to enable for this application, if the `protocol` is `icmp`. Must be one of +`network`, `host`, `protocol`, `port`, `df`, `admin`. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_security_association.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_security_association.html.markdown new file mode 100644 index 000000000..49207c879 --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_security_association.html.markdown @@ -0,0 +1,29 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_security_association" +sidebar_current: "docs-oracleopc-resource-security-association" +description: |- + Creates and manages a security association in an OPC identity domain. +--- + +# opc\_compute\_security\_association + +The ``opc_compute_security_association`` resource creates and manages an association between an instance and a security +list in an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_security_association" "test_instance_sec_list_1" { + vcable = "${opc_compute_instance.test_instance.vcable}" + seclist = "${opc_compute_security_list.sec_list1.name}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `vcable` - (Required) The `vcable` of the instance to associate to the security list. + +* `seclist` - (Required) The name of the security list to associate the instance to. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_security_ip_list.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_security_ip_list.html.markdown new file mode 100644 index 000000000..62f40d839 --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_security_ip_list.html.markdown @@ -0,0 +1,28 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_security_ip_list" +sidebar_current: "docs-oracleopc-resource-security-ip-list" +description: |- + Creates and manages a security IP list in an OPC identity domain. +--- + +# opc\_compute\_security\_ip\_list + +The ``opc_compute_security_ip_list`` resource creates and manages a security IP list in an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_security_ip_list" "sec_ip_list1" { + name = "sec-ip-list1" + ip_entries = ["217.138.34.4"] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The unique (within the identity domain) name of the security IP list. + +* `ip_entries` - (Required) The IP addresses to include in the list. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_security_list.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_security_list.html.markdown new file mode 100644 index 000000000..64547a41e --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_security_list.html.markdown @@ -0,0 +1,33 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_security_list" +sidebar_current: "docs-oracleopc-resource-security-list" +description: |- + Creates and manages a security list in an OPC identity domain. +--- + +# opc\_compute\_security\_list + +The ``opc_compute_security_list`` resource creates and manages a security list in an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_security_list" "sec_list1" { + name = "sec-list-1" + policy = "permit" + outbound_cidr_policy = "deny" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The unique (within the identity domain) name of the security list. + +* `policy` - (Required) The policy to apply to instances associated with this list. Must be one of `permit`, +`reject` (packets are dropped but a reply is sent) and `deny` (packets are dropped and no reply is sent). + +* `output_cidr_policy` - (Required) The policy for outbound traffic from the security list.Must be one of `permit`, +`reject` (packets are dropped but a reply is sent) and `deny` (packets are dropped and no reply is sent). diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_security_rule.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_security_rule.html.markdown new file mode 100644 index 000000000..6497b0265 --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_security_rule.html.markdown @@ -0,0 +1,46 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_security_rule" +sidebar_current: "docs-oracleopc-resource-security-rule" +description: |- + Creates and manages a security rule in an OPC identity domain. +--- + +# opc\_compute\_ip\_reservation + +The ``opc_compute_security_rule`` resource creates and manages a security rule in an OPC identity domain, which joins +together a source security list (or security IP list), a destination security list (or security IP list), and a security +application. + +## Example Usage + +``` +resource "opc_compute_security_rule" "test_rule" { + name = "test" + source_list = "seclist:${opc_compute_security_list.sec-list1.name}" + destination_list = "seciplist:${opc_compute_security_ip_list.sec-ip-list1.name}" + action = "permit" + application = "${opc_compute_security_application.spring-boot.name}" + disabled = false +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The unique (within the identity domain) name of the security rule. + +* `source_list` - (Required) The source security list (prefixed with `seclist:`), or security IP list (prefixed with +`seciplist:`). + + * `destination_list` - (Required) The destination security list (prefixed with `seclist:`), or security IP list (prefixed with + `seciplist:`). + +* `application` - (Required) The name of the application to which the rule applies. + +* `action` - (Required) Whether to `permit`, `refuse` or `deny` packets to which this rule applies. This will ordinarily +be `permit`. + +* `disabled` - (Required) Whether to disable this security rule. This is useful if you want to temporarily disable a rule +without removing it outright from your Terraform resource definition. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_ssh_key.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_ssh_key.html.markdown new file mode 100644 index 000000000..ff85467d8 --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_ssh_key.html.markdown @@ -0,0 +1,32 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_ssh_key" +sidebar_current: "docs-oracleopc-resource-ssh-key" +description: |- + Creates and manages an SSH key in an OPC identity domain. +--- + +# opc\_compute\_ssh_key + +The ``opc_compute_ssh_key`` resource creates and manages an SSH key in an OPC identity domain. + +## Example Usage + +``` +resource "opc_compute_ssh_key" "%s" { + name = "test-key" + key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqw6JwbjIk..." + enabled = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The unique (within this identity domain) name of the SSH key. + +* `key` - (Required) The SSH key itself + +* `enabled` - (Required) Whether or not the key is enabled. This is useful if you want to temporarily disable an SSH key, +without removing it entirely from your Terraform resource definition. diff --git a/website/source/docs/providers/oracleopc/r/opc_compute_storage_volume.html.markdown b/website/source/docs/providers/oracleopc/r/opc_compute_storage_volume.html.markdown new file mode 100644 index 000000000..4b30b59ed --- /dev/null +++ b/website/source/docs/providers/oracleopc/r/opc_compute_storage_volume.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "oracleopc" +page_title: "Oracle: opc_compute_storage_volume" +sidebar_current: "docs-oracleopc-resource-storage-volume" +description: |- + Creates and manages a storage volume in an OPC identity domain. +--- + +# opc\_compute\_storage\_volume + +The ``opc_compute_storage_volume`` resource creates and manages a storage volume in an OPC identity domain. + +~> **Caution:** The ``opc_compute_storage_volume`` resource can completely delete your +storage volume just as easily as it can create it. To avoid costly accidents, +consider setting +[``prevent_destroy``](/docs/configuration/resources.html#prevent_destroy) +on your storage volume resources as an extra safety measure. + +## Example Usage + +``` +resource "opc_compute_storage_volume" "test_volume" { + size = "3g" + description = "My storage volume" + name = "test_volume_a" + tags = ["xyzzy", "quux"] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The unique (within this identity domain) name of the storage volume. + +* `size` - (Required) The size of the storage instance. + +* `description` - (Optional) A description of the storage volume. + +* `tags` - (Optional) A list of tags to apply to the storage volume. + +* `bootableImage` - (Optional) The name of the bootable image the storage volume is loaded with. + +* `bootableImageVersion` - (Optional) The version of the bootable image specified in `bootableImage` to use. + +* `snapshot` - (Optional) The snapshot to initialise the storage volume with. This has two nested properties: `name`, +for the name of the snapshot to use, and `account` for the name of the snapshot account to use. + +* `snapshotId` - (Optional) The id of the snapshot to initialise the storage volume with. diff --git a/website/source/layouts/oracleopc.erb b/website/source/layouts/oracleopc.erb new file mode 100644 index 000000000..a9d9579f8 --- /dev/null +++ b/website/source/layouts/oracleopc.erb @@ -0,0 +1,59 @@ +<% wrap_layout :inner do %> +<% content_for :sidebar do %> +
+<% end %> + +<%= yield %> +<% end %>