diff --git a/cloudstack/provider.go b/cloudstack/provider.go index 5aad7c55..988ffa57 100644 --- a/cloudstack/provider.go +++ b/cloudstack/provider.go @@ -93,43 +93,51 @@ func Provider() *schema.Provider { }, ResourcesMap: map[string]*schema.Resource{ - "cloudstack_affinity_group": resourceCloudStackAffinityGroup(), - "cloudstack_attach_volume": resourceCloudStackAttachVolume(), - "cloudstack_autoscale_vm_profile": resourceCloudStackAutoScaleVMProfile(), - "cloudstack_disk": resourceCloudStackDisk(), - "cloudstack_egress_firewall": resourceCloudStackEgressFirewall(), - "cloudstack_firewall": resourceCloudStackFirewall(), - "cloudstack_host": resourceCloudStackHost(), - "cloudstack_instance": resourceCloudStackInstance(), - "cloudstack_ipaddress": resourceCloudStackIPAddress(), - "cloudstack_kubernetes_cluster": resourceCloudStackKubernetesCluster(), - "cloudstack_kubernetes_version": resourceCloudStackKubernetesVersion(), - "cloudstack_loadbalancer_rule": resourceCloudStackLoadBalancerRule(), - "cloudstack_network": resourceCloudStackNetwork(), - "cloudstack_network_acl": resourceCloudStackNetworkACL(), - "cloudstack_network_acl_rule": resourceCloudStackNetworkACLRule(), - "cloudstack_nic": resourceCloudStackNIC(), - "cloudstack_port_forward": resourceCloudStackPortForward(), - "cloudstack_private_gateway": resourceCloudStackPrivateGateway(), - "cloudstack_secondary_ipaddress": resourceCloudStackSecondaryIPAddress(), - "cloudstack_security_group": resourceCloudStackSecurityGroup(), - "cloudstack_security_group_rule": resourceCloudStackSecurityGroupRule(), - "cloudstack_ssh_keypair": resourceCloudStackSSHKeyPair(), - "cloudstack_static_nat": resourceCloudStackStaticNAT(), - "cloudstack_static_route": resourceCloudStackStaticRoute(), - "cloudstack_template": resourceCloudStackTemplate(), - "cloudstack_vpc": resourceCloudStackVPC(), - "cloudstack_vpn_connection": resourceCloudStackVPNConnection(), - "cloudstack_vpn_customer_gateway": resourceCloudStackVPNCustomerGateway(), - "cloudstack_vpn_gateway": resourceCloudStackVPNGateway(), - "cloudstack_network_offering": resourceCloudStackNetworkOffering(), - "cloudstack_disk_offering": resourceCloudStackDiskOffering(), - "cloudstack_volume": resourceCloudStackVolume(), - "cloudstack_zone": resourceCloudStackZone(), - "cloudstack_service_offering": resourceCloudStackServiceOffering(), - "cloudstack_account": resourceCloudStackAccount(), - "cloudstack_user": resourceCloudStackUser(), - "cloudstack_domain": resourceCloudStackDomain(), + "cloudstack_affinity_group": resourceCloudStackAffinityGroup(), + "cloudstack_attach_volume": resourceCloudStackAttachVolume(), + "cloudstack_autoscale_vm_profile": resourceCloudStackAutoScaleVMProfile(), + "cloudstack_cluster": resourceCloudStackCluster(), + "cloudstack_disk": resourceCloudStackDisk(), + "cloudstack_egress_firewall": resourceCloudStackEgressFirewall(), + "cloudstack_firewall": resourceCloudStackFirewall(), + "cloudstack_host": resourceCloudStackHost(), + "cloudstack_instance": resourceCloudStackInstance(), + "cloudstack_ipaddress": resourceCloudStackIPAddress(), + "cloudstack_kubernetes_cluster": resourceCloudStackKubernetesCluster(), + "cloudstack_kubernetes_version": resourceCloudStackKubernetesVersion(), + "cloudstack_loadbalancer_rule": resourceCloudStackLoadBalancerRule(), + "cloudstack_network": resourceCloudStackNetwork(), + "cloudstack_network_acl": resourceCloudStackNetworkACL(), + "cloudstack_network_acl_rule": resourceCloudStackNetworkACLRule(), + "cloudstack_network_service_provider_state": resourceCloudStackNetworkServiceProviderState(), + "cloudstack_nic": resourceCloudStackNIC(), + "cloudstack_physical_network": resourceCloudStackPhysicalNetwork(), + "cloudstack_pod": resourceCloudStackPod(), + "cloudstack_port_forward": resourceCloudStackPortForward(), + "cloudstack_private_gateway": resourceCloudStackPrivateGateway(), + "cloudstack_secondary_ipaddress": resourceCloudStackSecondaryIPAddress(), + "cloudstack_secondary_storage": resourceCloudStackSecondaryStorage(), + "cloudstack_security_group": resourceCloudStackSecurityGroup(), + "cloudstack_security_group_rule": resourceCloudStackSecurityGroupRule(), + "cloudstack_ssh_keypair": resourceCloudStackSSHKeyPair(), + "cloudstack_static_nat": resourceCloudStackStaticNAT(), + "cloudstack_static_route": resourceCloudStackStaticRoute(), + "cloudstack_storage_pool": resourceCloudStackStoragePool(), + "cloudstack_template": resourceCloudStackTemplate(), + "cloudstack_traffic_type": resourceCloudStackTrafficType(), + "cloudstack_vpc": resourceCloudStackVPC(), + "cloudstack_vpn_connection": resourceCloudStackVPNConnection(), + "cloudstack_vpn_customer_gateway": resourceCloudStackVPNCustomerGateway(), + "cloudstack_vpn_gateway": resourceCloudStackVPNGateway(), + "cloudstack_network_offering": resourceCloudStackNetworkOffering(), + "cloudstack_disk_offering": resourceCloudStackDiskOffering(), + "cloudstack_vlan_ip_range": resourceCloudstackVlanIpRange(), + "cloudstack_volume": resourceCloudStackVolume(), + "cloudstack_zone": resourceCloudStackZone(), + "cloudstack_service_offering": resourceCloudStackServiceOffering(), + "cloudstack_account": resourceCloudStackAccount(), + "cloudstack_user": resourceCloudStackUser(), + "cloudstack_domain": resourceCloudStackDomain(), }, ConfigureFunc: providerConfigure, diff --git a/cloudstack/resource_cloudstack_cluster.go b/cloudstack/resource_cloudstack_cluster.go new file mode 100644 index 00000000..48375359 --- /dev/null +++ b/cloudstack/resource_cloudstack_cluster.go @@ -0,0 +1,262 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackCluster() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackClusterCreate, + Read: resourceCloudStackClusterRead, + Update: resourceCloudStackClusterUpdate, + Delete: resourceCloudStackClusterDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "allocation_state": { + Description: "Allocation state of this cluster for allocation of new resources", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "cluster_name": { + Description: "the cluster name", + Type: schema.TypeString, + Required: true, + }, + "cluster_type": { + Description: "ype of the cluster: CloudManaged, ExternalManaged", + Type: schema.TypeString, + Required: true, + }, + "guest_vswitch_name": { + Description: "Name of virtual switch used for guest traffic in the cluster. This would override zone wide traffic label setting.", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "guest_vswitch_type": { + Description: "Type of virtual switch used for guest traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "hypervisor": { + Description: "hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator,Ovm3", + Type: schema.TypeString, + Required: true, + }, + "ovm3_cluster": { + Description: "Ovm3 native OCFS2 clustering enabled for cluster", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "ovm3_pool": { + Description: "Ovm3 native pooling enabled for cluster", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "ovm3_vip": { + Description: "Ovm3 vip to use for pool (and cluster)", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "password": { + Description: "the password for the host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "public_vswitch_name": { + Description: "Name of virtual switch used for public traffic in the cluster. This would override zone wide traffic label setting.", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "public_vswitch_type": { + Description: "Type of virtual switch used for public traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "pod_id": { + Description: "Type of virtual switch used for public traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)", + Type: schema.TypeString, + Required: true, + }, + "url": { + Description: "the URL", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "username": { + Description: "the username for the cluster", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "vsm_ip_address": { + Description: "the ipaddress of the VSM associated with this cluster", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "vsm_password": { + Description: "the password for the VSM associated with this cluster", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "vsm_username": { + Description: "the username for the VSM associated with this cluster", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "zone_id": { + Description: "the Zone ID for the cluster", + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceCloudStackClusterCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Cluster.NewAddClusterParams(d.Get("cluster_name").(string), d.Get("cluster_type").(string), d.Get("hypervisor").(string), d.Get("pod_id").(string), d.Get("zone_id").(string)) + if v, ok := d.GetOk("allocation_state"); ok { + p.SetAllocationstate(v.(string)) + } + if v, ok := d.GetOk("guest_vswitch_name"); ok { + p.SetGuestvswitchname(v.(string)) + } + if v, ok := d.GetOk("guest_vswitch_type"); ok { + p.SetGuestvswitchtype(v.(string)) + } + if v, ok := d.GetOk("hypervisor"); ok { + p.SetHypervisor(v.(string)) + } + if v, ok := d.GetOk("ovm3_cluster"); ok { + p.SetOvm3cluster(v.(string)) + } + if v, ok := d.GetOk("ovm3_pool"); ok { + p.SetOvm3pool(v.(string)) + } + if v, ok := d.GetOk("ovm3_vip"); ok { + p.SetOvm3vip(v.(string)) + } + if v, ok := d.GetOk("password"); ok { + p.SetPassword(v.(string)) + } + if v, ok := d.GetOk("public_vswitch_name"); ok { + p.SetPublicvswitchname(v.(string)) + } + if v, ok := d.GetOk("public_vswitch_type"); ok { + p.SetPublicvswitchtype(v.(string)) + } + if v, ok := d.GetOk("url"); ok { + p.SetUrl(v.(string)) + } + if v, ok := d.GetOk("username"); ok { + p.SetUsername(v.(string)) + } + if v, ok := d.GetOk("vsm_ip_address"); ok { + p.SetVsmipaddress(v.(string)) + } + if v, ok := d.GetOk("vsm_password"); ok { + p.SetVsmpassword(v.(string)) + } + if v, ok := d.GetOk("vsm_username"); ok { + p.SetVsmusername(v.(string)) + } + + r, err := cs.Cluster.AddCluster(p) + if err != nil { + return err + } + d.SetId(r.Id) + + return resourceCloudStackClusterRead(d, meta) +} + +func resourceCloudStackClusterRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + r, _, err := cs.Cluster.GetClusterByID(d.Id()) + if err != nil { + return err + } + + d.Set("allocation_state", r.Allocationstate) + d.Set("cluster_type", r.Clustertype) + d.Set("hypervisor", r.Hypervisortype) + d.Set("cluster_name", r.Name) + d.Set("ovm3_vip", r.Ovm3vip) + d.Set("pod_id", r.Podid) + d.Set("zone_id", r.Zoneid) + + return nil +} + +func resourceCloudStackClusterUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Cluster.NewUpdateClusterParams(d.Id()) + if v, ok := d.GetOk("allocation_state"); ok { + p.SetAllocationstate(v.(string)) + } + if v, ok := d.GetOk("cluster_name"); ok { + p.SetClustername(v.(string)) + } + if v, ok := d.GetOk("cluster_type"); ok { + p.SetClustertype(v.(string)) + } + if v, ok := d.GetOk("hypervisor"); ok { + p.SetHypervisor(v.(string)) + } + + _, err := cs.Cluster.UpdateCluster(p) + if err != nil { + return err + } + + return resourceCloudStackClusterRead(d, meta) +} + +func resourceCloudStackClusterDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + _, err := cs.Cluster.DeleteCluster(cs.Cluster.NewDeleteClusterParams(d.Id())) + if err != nil { + return err + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_cluster_test.go b/cloudstack/resource_cloudstack_cluster_test.go new file mode 100644 index 00000000..6c4ec939 --- /dev/null +++ b/cloudstack/resource_cloudstack_cluster_test.go @@ -0,0 +1,65 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStackCluster_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackCluster_basic, + }, + }, + }) +} + +const testAccCloudStackCluster_basic = ` +resource "cloudstack_zone" "test" { + name = "acc_zone" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_pod" "test" { + allocation_state = "Disabled" + gateway = "172.30.0.1" + name = "acc_pod" + netmask = "255.255.240.0" + start_ip = "172.30.0.2" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_cluster" "test" { + cluster_name = "acc_cluster" + cluster_type = "CloudManaged" + hypervisor = "KVM" + pod_id = cloudstack_pod.test.id + zone_id = cloudstack_zone.test.id +} +` diff --git a/cloudstack/resource_cloudstack_network_service_provider_state.go b/cloudstack/resource_cloudstack_network_service_provider_state.go new file mode 100644 index 00000000..bcdc17d8 --- /dev/null +++ b/cloudstack/resource_cloudstack_network_service_provider_state.go @@ -0,0 +1,219 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "fmt" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackNetworkServiceProviderState() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackNetworkServiceProviderStateUpdate, + Read: resourceCloudStackNetworkServiceProviderStateRead, + Update: resourceCloudStackNetworkServiceProviderStateUpdate, + Delete: resourceCloudStackNetworkServiceProviderStateDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Description: "the name for the physical network service provider", + Type: schema.TypeString, + Required: true, + }, + "physical_network_id": { + Description: "the Physical Network ID to add the provider to", + Type: schema.TypeString, + Required: true, + }, + "enabled": { + Description: "state of the network provider", + Type: schema.TypeBool, + Required: true, + }, + }, + } +} + +func resourceCloudStackNetworkServiceProviderStateRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + nsp, err := getNetworkServiceProvider(cs, d) + if err != nil { + return err + } + + d.SetId(nsp.Id) + if nsp.State == "Enabled" { + d.Set("enabled", true) + } else { + d.Set("enabled", false) + } + + return nil +} + +func resourceCloudStackNetworkServiceProviderStateUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Network service provider + nsp, err := getNetworkServiceProvider(cs, d) + if err != nil { + return err + } + + switch d.Get("name") { + case "VirtualRouter", "VpcVirtualRouter": + err := virtualRouterElementState(cs, nsp, d.Get("enabled").(bool)) + if err != nil { + return err + } + case "InternalLbVm": + err := internalLbVmElementState(cs, nsp, d.Get("enabled").(bool)) + if err != nil { + return err + } + case "ConfigDrive": + // No elements to configure + default: + return fmt.Errorf("Service provider (%s) name not supported.", d.Get("name")) + } + + // Service provider state + pUNSPP := cs.Network.NewUpdateNetworkServiceProviderParams(nsp.Id) + if d.Get("enabled").(bool) { + pUNSPP.SetState("Enabled") + } else { + pUNSPP.SetState("Disabled") + } + _, err = cs.Network.UpdateNetworkServiceProvider(pUNSPP) + if err != nil { + return err + } + + return resourceCloudStackNetworkServiceProviderStateRead(d, meta) +} + +func resourceCloudStackNetworkServiceProviderStateDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Network.NewUpdateNetworkServiceProviderParams(d.Id()) + p.SetState("Disabled") + + _, err := cs.Network.UpdateNetworkServiceProvider(p) + if err != nil { + return err + } + + d.SetId("") + + return nil +} + +func getNetworkServiceProvider(cs *cloudstack.CloudStackClient, d *schema.ResourceData) (*cloudstack.NetworkServiceProvider, error) { + p := cs.Network.NewListNetworkServiceProvidersParams() + if _, ok := d.GetOk("name"); ok { + p.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("physical_network_id"); ok { + p.SetPhysicalnetworkid(d.Get("physical_network_id").(string)) + } + + // list network service providers + r, err := cs.Network.ListNetworkServiceProviders(p) + if err != nil { + return nil, err + } + + for _, nsp := range r.NetworkServiceProviders { + if _, ok := d.GetOk("name"); ok { + if nsp.Name == d.Get("name").(string) { + return nsp, nil + } + } else if nsp.Id == d.Id() { + return nsp, nil + } + } + + return nil, fmt.Errorf("Service provider element id not found.") +} + +func virtualRouterElementState(cs *cloudstack.CloudStackClient, nsp *cloudstack.NetworkServiceProvider, state bool) error { + // VirtualRouterElement state + p := cs.Router.NewListVirtualRouterElementsParams() + p.SetNspid(nsp.Id) + + vre, err := cs.Router.ListVirtualRouterElements(p) + if err != nil { + return err + } + + var vreID string + for _, e := range vre.VirtualRouterElements { + if nsp.Id == e.Nspid { + vreID = e.Id + break + } + return fmt.Errorf("Service provider element id (nspod) not found: %s.", nsp.Id) + } + + _, err = cs.Router.ConfigureVirtualRouterElement(cs.Router.NewConfigureVirtualRouterElementParams(state, vreID)) + if err != nil { + return err + } + + return nil + +} + +func internalLbVmElementState(cs *cloudstack.CloudStackClient, nsp *cloudstack.NetworkServiceProvider, state bool) error { + // InternalLoadBalancerElement state + p := cs.InternalLB.NewListInternalLoadBalancerElementsParams() + p.SetNspid(nsp.Id) + + ilbe, err := cs.InternalLB.ListInternalLoadBalancerElements(p) + if err != nil { + return err + } + + var ilbeID string + for _, e := range ilbe.InternalLoadBalancerElements { + if nsp.Id == e.Nspid { + ilbeID = e.Id + break + } + return fmt.Errorf("Service provider element id (nspod) not found: %s.", nsp.Id) + } + + ilvm, err := cs.InternalLB.ConfigureInternalLoadBalancerElement(cs.InternalLB.NewConfigureInternalLoadBalancerElementParams(state, ilbeID)) + if err != nil { + return err + } + + _, err = cs.InternalLB.ConfigureInternalLoadBalancerElement(cs.InternalLB.NewConfigureInternalLoadBalancerElementParams(state, ilvm.Id)) + if err != nil { + return err + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_network_service_provider_state_test.go b/cloudstack/resource_cloudstack_network_service_provider_state_test.go new file mode 100644 index 00000000..be14ab65 --- /dev/null +++ b/cloudstack/resource_cloudstack_network_service_provider_state_test.go @@ -0,0 +1,133 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudstackNetworkServiceProviderState_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudstackNetworkServiceProviderState_basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.virtualrouter", "enabled", "true"), + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.vpcvirtualrouter", "enabled", "true"), + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.internallbvm", "enabled", "false"), + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.configdrive", "enabled", "false"), + ), + }, + { + Config: testAccCloudstackNetworkServiceProviderState_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.virtualrouter", "enabled", "false"), + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.vpcvirtualrouter", "enabled", "false"), + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.internallbvm", "enabled", "true"), + resource.TestCheckResourceAttr("cloudstack_network_service_provider_state.configdrive", "enabled", "true"), + ), + }, + }, + }) +} + +const testAccCloudstackNetworkServiceProviderState_basic = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_network_service_provider_state" "virtualrouter" { + name = "VirtualRouter" + physical_network_id = cloudstack_physical_network.test.id + enabled = true +} +resource "cloudstack_network_service_provider_state" "vpcvirtualrouter" { + name = "VpcVirtualRouter" + physical_network_id = cloudstack_physical_network.test.id + enabled = true +} +resource "cloudstack_network_service_provider_state" "internallbvm" { + name = "InternalLbVm" + physical_network_id = cloudstack_physical_network.test.id + enabled = false +} +resource "cloudstack_network_service_provider_state" "configdrive" { + name = "ConfigDrive" + physical_network_id = cloudstack_physical_network.test.id + enabled = false +} +` + +const testAccCloudstackNetworkServiceProviderState_update = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_network_service_provider_state" "virtualrouter" { + name = "VirtualRouter" + physical_network_id = cloudstack_physical_network.test.id + enabled = false +} +resource "cloudstack_network_service_provider_state" "vpcvirtualrouter" { + name = "VpcVirtualRouter" + physical_network_id = cloudstack_physical_network.test.id + enabled = false +} +resource "cloudstack_network_service_provider_state" "internallbvm" { + name = "InternalLbVm" + physical_network_id = cloudstack_physical_network.test.id + enabled = true +} +resource "cloudstack_network_service_provider_state" "configdrive" { + name = "ConfigDrive" + physical_network_id = cloudstack_physical_network.test.id + enabled = true +} +` diff --git a/cloudstack/resource_cloudstack_physical_network.go b/cloudstack/resource_cloudstack_physical_network.go new file mode 100644 index 00000000..69e8d7db --- /dev/null +++ b/cloudstack/resource_cloudstack_physical_network.go @@ -0,0 +1,174 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "fmt" + "strings" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackPhysicalNetwork() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackPhysicalNetworkCreate, + Read: resourceCloudStackPhysicalNetworkRead, + Update: resourceCloudStackPhysicalNetworkUpdate, + Delete: resourceCloudStackPhysicalNetworkDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "broadcast_domain_range": { + Description: "the broadcast domain range for the physical network[Pod or Zone]. In Acton release it can be Zone only in Advance zone, and Pod in Basic", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "domain_id": { + Description: "domain ID of the account owning a physical network", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "isolation_methods": { + Description: "the isolation method for the physical network[VLAN/L3/GRE]", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "name": { + Description: "the name of the physical network", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "network_speed": { + Description: "the speed for the physical network[1G/10G]", + Type: schema.TypeString, + Optional: true, + }, + "tags": { + Description: "Tag the physical network", + Type: schema.TypeString, + Optional: true, + }, + "vlan": { + Description: "the VLAN for the physical network", + Type: schema.TypeString, + Optional: true, + }, + "zone_id": { + Description: "zone id of the physical network", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudStackPhysicalNetworkCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Network.NewCreatePhysicalNetworkParams(d.Get("name").(string), d.Get("zone_id").(string)) + if v, ok := d.GetOk("broadcast_domain_range"); ok { + p.SetBroadcastdomainrange(strings.ToUpper(v.(string))) + } + if v, ok := d.GetOk("domain_id"); ok { + p.SetDomainid(v.(string)) + } + if v, ok := d.GetOk("isolation_methods"); ok { + p.SetIsolationmethods([]string{v.(string)}) + } + if v, ok := d.GetOk("network_speed"); ok { + p.SetNetworkspeed(v.(string)) + } + if v, ok := d.GetOk("tags"); ok { + p.SetTags([]string{v.(string)}) + } + if v, ok := d.GetOk("vlan"); ok { + p.SetVlan(v.(string)) + } + + r, err := cs.Network.CreatePhysicalNetwork(p) + if err != nil { + return err + } + + d.SetId(r.Id) + + return resourceCloudStackPhysicalNetworkRead(d, meta) +} + +func resourceCloudStackPhysicalNetworkRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + pn, _, err := cs.Network.GetPhysicalNetworkByID(d.Id()) + if err != nil { + return err + } + + d.Set("broadcast_domain_range", pn.Broadcastdomainrange) + d.Set("domain_id", pn.Domainid) + d.Set("isolation_methods", pn.Isolationmethods) + d.Set("name", pn.Name) + d.Set("network_speed", pn.Networkspeed) + d.Set("tags", pn.Tags) + d.Set("vlan", pn.Vlan) + d.Set("zone_id", pn.Zoneid) + + return nil +} + +func resourceCloudStackPhysicalNetworkUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Network.NewUpdatePhysicalNetworkParams(d.Id()) + if v, ok := d.GetOk("network_speed"); ok { + p.SetNetworkspeed(v.(string)) + } + if v, ok := d.GetOk("tags"); ok { + p.SetTags([]string{v.(string)}) + } + if v, ok := d.GetOk("vlan"); ok { + p.SetVlan(v.(string)) + } + + _, err := cs.Network.UpdatePhysicalNetwork(p) + if err != nil { + return fmt.Errorf("Error deleting physical network: %s", err) + } + + return resourceCloudStackPhysicalNetworkRead(d, meta) +} + +func resourceCloudStackPhysicalNetworkDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Network.NewDeletePhysicalNetworkParams(d.Id()) + _, err := cs.Network.DeletePhysicalNetwork(p) + if err != nil { + return fmt.Errorf("Error deleting phsyical network: %s", err) + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_physical_network_test.go b/cloudstack/resource_cloudstack_physical_network_test.go new file mode 100644 index 00000000..4ac9f744 --- /dev/null +++ b/cloudstack/resource_cloudstack_physical_network_test.go @@ -0,0 +1,81 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStackPhysicalNetwork_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackPhysicalNetwork_basic, + }, + { + Config: testAccCloudStackPhysicalNetwork_update, + }, + }, + }) +} + +const testAccCloudStackPhysicalNetwork_basic = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +` + +const testAccCloudStackPhysicalNetwork_update = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "10G" + tags = "vxlan" + zone_id = cloudstack_zone.test.id +} +` diff --git a/cloudstack/resource_cloudstack_pod.go b/cloudstack/resource_cloudstack_pod.go new file mode 100644 index 00000000..efbaddd7 --- /dev/null +++ b/cloudstack/resource_cloudstack_pod.go @@ -0,0 +1,171 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "strings" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackPod() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackPodCreate, + Read: resourceCloudStackPodRead, + Update: resourceCloudStackPodUpdate, + Delete: resourceCloudStackPodDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "allocation_state": { + Description: "Allocation state of this Pod for allocation of new resources", + Type: schema.TypeString, + Optional: true, + }, + "end_ip": { + Description: "he ending IP address for the Pod", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "gateway": { + Description: "the gateway for the Pod", + Type: schema.TypeString, + Required: true, + }, + "name": { + Description: "the name of the Pod", + Type: schema.TypeString, + Required: true, + }, + "netmask": { + Description: "the netmask for the Pod", + Type: schema.TypeString, + Required: true, + }, + "start_ip": { + Description: "the starting IP address for the Pod", + Type: schema.TypeString, + Required: true, + }, + "zone_id": { + Description: "the Zone ID in which the Pod will be created", + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceCloudStackPodCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Pod.NewCreatePodParams(d.Get("name").(string), d.Get("zone_id").(string)) + if v, ok := d.GetOk("allocation_state"); ok { + p.SetAllocationstate(v.(string)) + } + if v, ok := d.GetOk("end_ip"); ok { + p.SetEndip(v.(string)) + } + if v, ok := d.GetOk("gateway"); ok { + p.SetGateway(v.(string)) + } + if v, ok := d.GetOk("netmask"); ok { + p.SetNetmask(v.(string)) + } + if v, ok := d.GetOk("start_ip"); ok { + p.SetStartip(v.(string)) + } + if v, ok := d.GetOk("zone_id"); ok { + p.SetZoneid(v.(string)) + } + + r, err := cs.Pod.CreatePod(p) + if err != nil { + return err + } + + d.SetId(r.Id) + + return resourceCloudStackPodRead(d, meta) +} + +func resourceCloudStackPodRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + r, _, err := cs.Pod.GetPodByID(d.Id()) + if err != nil { + return err + } + + d.Set("allocation_state", r.Allocationstate) + d.Set("end_ip", strings.Join(r.Endip, " ")) + d.Set("gateway", r.Gateway) + d.Set("name", r.Name) + d.Set("netmask", r.Netmask) + d.Set("start_ip", strings.Join(r.Startip, " ")) + d.Set("zone_id", r.Zoneid) + + return nil +} + +func resourceCloudStackPodUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Pod.NewUpdatePodParams(d.Id()) + if v, ok := d.GetOk("allocation_state"); ok { + p.SetAllocationstate(v.(string)) + } + if v, ok := d.GetOk("end_ip"); ok { + p.SetEndip(v.(string)) + } + if v, ok := d.GetOk("gateway"); ok { + p.SetGateway(v.(string)) + } + if v, ok := d.GetOk("name"); ok { + p.SetName(v.(string)) + } + if v, ok := d.GetOk("netmask"); ok { + p.SetNetmask(v.(string)) + } + if v, ok := d.GetOk("start_ip"); ok { + p.SetStartip(v.(string)) + } + + _, err := cs.Pod.UpdatePod(p) + if err != nil { + return err + } + + return resourceCloudStackPodRead(d, meta) +} + +func resourceCloudStackPodDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + _, err := cs.Pod.DeletePod(cs.Pod.NewDeletePodParams(d.Id())) + if err != nil { + return err + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_pod_test.go b/cloudstack/resource_cloudstack_pod_test.go new file mode 100644 index 00000000..f80dd87d --- /dev/null +++ b/cloudstack/resource_cloudstack_pod_test.go @@ -0,0 +1,83 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStackPod_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackPod_basic, + }, + // { + // Config: testAccCloudStackPod_update, + // Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttr("cloudstack_pod.test", "name", "accpod2"), + // ), + // }, + }, + }) +} + +const testAccCloudStackPod_basic = ` +resource "cloudstack_zone" "test" { + name = "acc_zone" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_pod" "test" { + name = "acc_pod" + allocation_state = "Disabled" + gateway = "172.29.0.1" + netmask = "255.255.240.0" + start_ip = "172.29.0.2" + zone_id = cloudstack_zone.test.id +} +` + +const testAccCloudStackPod_update = ` +resource "cloudstack_zone" "test" { + name = "acc_zone" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_pod" "test" { + name = "acc_pod2" + allocation_state = "Disabled" + gateway = "172.29.0.1" + netmask = "255.255.240.0" + start_ip = "172.29.0.3" + zone_id = cloudstack_zone.test.id +` diff --git a/cloudstack/resource_cloudstack_secondary_storage.go b/cloudstack/resource_cloudstack_secondary_storage.go new file mode 100644 index 00000000..ea2d6439 --- /dev/null +++ b/cloudstack/resource_cloudstack_secondary_storage.go @@ -0,0 +1,118 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "fmt" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackSecondaryStorage() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackSecondaryStorageCreate, + Read: resourceCloudStackSecondaryStorageRead, + Delete: resourceCloudStackSecondaryStorageDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Description: "the name of the image store", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "storage_provider": { + Description: "the provider name of the image store", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "url": { + Description: "the url of the image store", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "zone_id": { + Description: "the Zone ID of the image store", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudStackSecondaryStorageCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.ImageStore.NewAddImageStoreParams(d.Get("storage_provider").(string)) + if v, ok := d.GetOk("name"); ok { + p.SetName(v.(string)) + } + if v, ok := d.GetOk("url"); ok { + p.SetUrl(v.(string)) + } + if v, ok := d.GetOk("zone_id"); ok { + p.SetZoneid(v.(string)) + } + + r, err := cs.ImageStore.AddImageStore(p) + if err != nil { + return err + } + + d.SetId(r.Id) + + return resourceCloudStackSecondaryStorageRead(d, meta) +} + +func resourceCloudStackSecondaryStorageRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + r, _, err := cs.ImageStore.GetImageStoreByID(d.Id()) + if err != nil { + return err + } + + d.Set("name", r.Name) + d.Set("storage_provider", r.Providername) + d.Set("url", r.Url) + d.Set("zone_id", r.Zoneid) + + return nil +} + +func resourceCloudStackSecondaryStorageDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + _, err := cs.ImageStore.DeleteImageStore(cs.ImageStore.NewDeleteImageStoreParams(d.Id())) + if err != nil { + return fmt.Errorf("Error deleting secondary storage: %s", err) + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_secondary_storage_test.go b/cloudstack/resource_cloudstack_secondary_storage_test.go new file mode 100644 index 00000000..7139e496 --- /dev/null +++ b/cloudstack/resource_cloudstack_secondary_storage_test.go @@ -0,0 +1,53 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStackSecondaryStorage_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackSecondaryStorage_basic, + }, + }, + }) +} + +const testAccCloudStackSecondaryStorage_basic = ` +data "cloudstack_zone" "test" { + filter { + name = "name" + value = "Sandbox-simulator" + } +} +resource "cloudstack_secondary_storage" "test" { + name = "acctest_secondarystorage" + storage_provider = "NFS" + url = "nfs://10.147.28.6:/export/home/sandbox/secondary" + zone_id = data.cloudstack_zone.test.id +} +` diff --git a/cloudstack/resource_cloudstack_storage_pool.go b/cloudstack/resource_cloudstack_storage_pool.go new file mode 100644 index 00000000..b83e8319 --- /dev/null +++ b/cloudstack/resource_cloudstack_storage_pool.go @@ -0,0 +1,215 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "fmt" + "strings" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackStoragePool() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackStoragePoolCreate, + Read: resourceCloudStackStoragePoolRead, + Update: resourceCloudStackStoragePoolUpdate, + Delete: resourceCloudStackStoragePoolDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "cluster_id": { + Description: "the cluster ID for the storage pool", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "hypervisor": { + Description: "hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "name": { + Description: "the name for the storage pool", + Type: schema.TypeString, + Required: true, + }, + "pod_id": { + Description: "the Pod ID for the storage pool", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "storage_provider": { + Description: "Storage provider for this pool", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "scope": { + Description: "the scope of the storage: cluster or zone", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "state": { + Description: "the state of the storage pool", + Type: schema.TypeString, + Optional: true, + Computed: true, + // "Maintenance","Disabled","Up", + }, + "tags": { + Description: "the tags for the storage pool", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "url": { + Description: "the URL of the storage pool", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "zone_id": { + Description: "the Zone ID for the storage pool", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudStackStoragePoolCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Pool.NewCreateStoragePoolParams(d.Get("name").(string), d.Get("url").(string), d.Get("zone_id").(string)) + if v, ok := d.GetOk("cluster_id"); ok { + p.SetClusterid(v.(string)) + } + if v, ok := d.GetOk("hypervisor"); ok { + p.SetHypervisor(v.(string)) + } + if v, ok := d.GetOk("name"); ok { + p.SetName(v.(string)) + } + if v, ok := d.GetOk("pod_id"); ok { + p.SetPodid(v.(string)) + } + if v, ok := d.GetOk("storage_provider"); ok { + p.SetProvider(v.(string)) + } + if v, ok := d.GetOk("scope"); ok { + p.SetScope(v.(string)) + } + if v, ok := d.GetOk("tags"); ok { + p.SetTags(v.(string)) + } + if v, ok := d.GetOk("url"); ok { + p.SetUrl(v.(string)) + } + if v, ok := d.GetOk("zone_id"); ok { + p.SetZoneid(v.(string)) + } + + r, err := cs.Pool.CreateStoragePool(p) + if err != nil { + return err + } + + d.SetId(r.Id) + + return resourceCloudStackStoragePoolRead(d, meta) +} + +func resourceCloudStackStoragePoolRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + r, _, err := cs.Pool.GetStoragePoolByID(d.Id()) + if err != nil { + return err + } + + d.Set("cluster_id", r.Clusterid) + d.Set("hypervisor", r.Hypervisor) + d.Set("name", r.Name) + d.Set("pod_id", r.Podid) + d.Set("storage_provider", r.Provider) + d.Set("scope", r.Scope) + d.Set("state", r.State) + d.Set("tags", r.Tags) + d.Set("zone_id", r.Zoneid) + + return nil +} + +func resourceCloudStackStoragePoolUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Pool.NewUpdateStoragePoolParams(d.Id()) + if v, ok := d.GetOk("capacity_bytes"); ok { + p.SetCapacitybytes(v.(int64)) + } + if v, ok := d.GetOk("capacity_iops"); ok { + p.SetCapacityiops(v.(int64)) + } + if v, ok := d.GetOk("name"); ok { + p.SetName(v.(string)) + } + if v, ok := d.GetOk("tags"); ok { + p.SetTags(strings.Split(v.(string), ",")) + } + + if v, ok := d.GetOk("state"); ok { + if v == "Up" { + p.SetEnabled(true) + } else if v == "Disabled" { + p.SetEnabled(false) + } else if v == "Maintenance" { + _, err := cs.StoragePool.EnableStorageMaintenance(cs.StoragePool.NewEnableStorageMaintenanceParams(d.Id())) + if err != nil { + return err + } + } + } + + _, err := cs.Pool.UpdateStoragePool(p) + if err != nil { + return err + } + + return resourceCloudStackStoragePoolRead(d, meta) +} + +func resourceCloudStackStoragePoolDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + _, err := cs.Pool.DeleteStoragePool(cs.Pool.NewDeleteStoragePoolParams(d.Id())) + if err != nil { + return fmt.Errorf("Error deleting storage pool: %s", err) + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_storage_pool_test.go b/cloudstack/resource_cloudstack_storage_pool_test.go new file mode 100644 index 00000000..649e267c --- /dev/null +++ b/cloudstack/resource_cloudstack_storage_pool_test.go @@ -0,0 +1,121 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStackStoragePool_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackStoragePoolConfig_basic, + }, + { + Config: testAccCloudStackStoragePoolConfig_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_storage_pool.test", "name", "accprimarystorage1"), + ), + }, + }, + }) +} + +const testAccCloudStackStoragePoolConfig_basic = ` +resource "cloudstack_zone" "test" { + name = "acc_zone" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_pod" "test" { + allocation_state = "Disabled" + gateway = "172.31.0.1" + name = "acc_pod" + netmask = "255.255.240.0" + start_ip = "172.31.0.2" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_cluster" "test" { + cluster_name = "acc_cluster" + cluster_type = "CloudManaged" + hypervisor = "KVM" + pod_id = cloudstack_pod.test.id + zone_id = cloudstack_zone.test.id +} + +resource "cloudstack_storage_pool" "test" { + name = "acc_primarystorage" + url = "nfs://10.147.28.6/export/home/sandbox/primary11" + zone_id = cloudstack_zone.test.id + cluster_id = cloudstack_cluster.test.id + pod_id = cloudstack_pod.test.id + scope = "CLUSTER" + hypervisor = "Simulator" + tags = "XYZ,123" +} +` + +const testAccCloudStackStoragePoolConfig_update = ` +resource "cloudstack_zone" "test" { + name = "acc_zone" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_pod" "test" { + allocation_state = "Disabled" + gateway = "172.31.0.1" + name = "acc_pod" + netmask = "255.255.240.0" + start_ip = "172.31.0.2" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_cluster" "test" { + cluster_name = "acc_cluster" + cluster_type = "CloudManaged" + hypervisor = "KVM" + pod_id = cloudstack_pod.test.id + zone_id = cloudstack_zone.test.id +} + +resource "cloudstack_storage_pool" "test" { + name = "acc_primarystorage1" + url = "nfs://10.147.28.6/export/home/sandbox/primary11" + zone_id = cloudstack_zone.test.id + cluster_id = cloudstack_cluster.test.id + pod_id = cloudstack_pod.test.id + scope = "CLUSTER" + hypervisor = "Simulator" + state = "Maintenance" + tags = "XYZ,123,456" +} +` diff --git a/cloudstack/resource_cloudstack_traffic_type.go b/cloudstack/resource_cloudstack_traffic_type.go new file mode 100644 index 00000000..559a0b7b --- /dev/null +++ b/cloudstack/resource_cloudstack_traffic_type.go @@ -0,0 +1,207 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "fmt" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudStackTrafficType() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackTrafficTypeCreate, + Read: resourceCloudStackTrafficTypeRead, + // Update: resourceCloudStackTrafficTypeUpdate, + Delete: resourceCloudStackTrafficTypeDelete, + Schema: map[string]*schema.Schema{ + "hyperv_network_label": { + Description: "The network name label of the physical device dedicated to this traffic on a Hyperv host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "isolation_method": { + Description: "Used if physical network has multiple isolation types and traffic type is public. Choose which isolation method. Valid options currently 'vlan' or 'vxlan', defaults to 'vlan'.", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "kvm_network_label": { + Description: "The network name label of the physical device dedicated to this traffic on a KVM host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "ovm3_network_label": { + Description: "The network name of the physical device dedicated to this traffic on an OVM3 host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "physical_network_id": { + Description: "the Physical Network ID", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "traffic_type": { + Description: "the trafficType to be added to the physical network", + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateTrafficType, + }, + "vlan": { + Description: "The VLAN id to be used for Management traffic by VMware host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "vmware_network_label": { + Description: "The network name label of the physical device dedicated to this traffic on a VMware host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "xen_network_label": { + Description: "The network name label of the physical device dedicated to this traffic on a XenServer host", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudStackTrafficTypeCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Usage.NewAddTrafficTypeParams(d.Get("physical_network_id").(string), d.Get("traffic_type").(string)) + if v, ok := d.GetOk("hyperv_network_label"); ok { + p.SetHypervnetworklabel(v.(string)) + } + if v, ok := d.GetOk("isolation_method"); ok { + p.SetIsolationmethod(v.(string)) + } + if v, ok := d.GetOk("kvm_network_label"); ok { + p.SetKvmnetworklabel(v.(string)) + } + if v, ok := d.GetOk("ovm3_network_label"); ok { + p.SetOvm3networklabel(v.(string)) + } + if v, ok := d.GetOk("vlan"); ok { + p.SetVlan(v.(string)) + } + if v, ok := d.GetOk("vmware_network_label"); ok { + p.SetVmwarenetworklabel(v.(string)) + } + if v, ok := d.GetOk("xen_network_label"); ok { + p.SetXennetworklabel(v.(string)) + } + + r, err := cs.Usage.AddTrafficType(p) + if err != nil { + return err + } + d.SetId(r.Id) + d.Set("physical_network_id", d.Get("physical_network_id").(string)) + + // + d.Set("hyperv_network_label", r.Hypervnetworklabel) + d.Set("kvm_network_label", r.Kvmnetworklabel) + d.Set("ovm3_network_label", r.Ovm3networklabel) + d.Set("traffic_type", r.Traffictype) + d.Set("vmware_network_label", r.Vmwarenetworklabel) + d.Set("xen_network_label", r.Xennetworklabel) + + return resourceCloudStackTrafficTypeRead(d, meta) +} + +func resourceCloudStackTrafficTypeRead(d *schema.ResourceData, meta interface{}) error { + // Nothing to read. While these fields are returned by the API + // they are not documented in the client or ListApi spec. + // see https://github.com/apache/cloudstack/issues/7837 + + return nil +} + +func resourceCloudStackTrafficTypeUpdate(d *schema.ResourceData, meta interface{}) error { + // All fields are ForceNew or Computed w/out Optional, Update is superfluous + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Usage.NewUpdateTrafficTypeParams(d.Id()) + if v, ok := d.GetOk("hyperv_network_label"); ok { + p.SetHypervnetworklabel(v.(string)) + } + if v, ok := d.GetOk("kvm_network_label"); ok { + p.SetKvmnetworklabel(v.(string)) + } + if v, ok := d.GetOk("ovm3_network_label"); ok { + p.SetOvm3networklabel(v.(string)) + } + if v, ok := d.GetOk("vmware_network_label"); ok { + p.SetVmwarenetworklabel(v.(string)) + } + if v, ok := d.GetOk("xen_network_label"); ok { + p.SetXennetworklabel(v.(string)) + } + + r, err := cs.Usage.UpdateTrafficType(p) + if err != nil { + return err + } + + d.Set("hyperv_network_label", r.Hypervnetworklabel) + d.Set("kvm_network_label", r.Kvmnetworklabel) + d.Set("ovm3_network_label", r.Ovm3networklabel) + d.Set("traffic_type", r.Traffictype) + d.Set("vmware_network_label", r.Vmwarenetworklabel) + d.Set("xen_network_label", r.Xennetworklabel) + + return resourceCloudStackTrafficTypeRead(d, meta) +} + +func resourceCloudStackTrafficTypeDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + _, err := cs.Usage.DeleteTrafficType(cs.Usage.NewDeleteTrafficTypeParams(d.Id())) + if err != nil { + return fmt.Errorf("Error deleting traffic type: %s", err) + } + + return nil +} + +func validateTrafficType(v interface{}, _ string) (warnings []string, errors []error) { + input := v.(string) + + allowed := []string{"Public", "Guest", "Management", "Storage"} + + for _, str := range allowed { + if str == input { + return + } + } + errors = append(errors, fmt.Errorf("traffic_type identifier (%q) not found, expecting %v", input, allowed)) + + return warnings, errors +} diff --git a/cloudstack/resource_cloudstack_traffic_type_test.go b/cloudstack/resource_cloudstack_traffic_type_test.go new file mode 100644 index 00000000..8d7978a8 --- /dev/null +++ b/cloudstack/resource_cloudstack_traffic_type_test.go @@ -0,0 +1,94 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStacktrafficType_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStacktrafficType_basic, + }, + { + Config: testAccCloudStacktrafficType_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_traffic_type.management", "kvm_network_label", "csmgmt2"), + ), + }, + }, + }) +} + +const testAccCloudStacktrafficType_basic = ` +resource "cloudstack_zone" "test" { + name = "acctestTrafficType" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "acctestTrafficType" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_traffic_type" "management" { + physical_network_id = cloudstack_physical_network.test.id + traffic_type = "Management" + kvm_network_label = "csmgmt" +} +` + +const testAccCloudStacktrafficType_update = ` +resource "cloudstack_zone" "test" { + name = "acctestTrafficType" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "acctestTrafficType" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_traffic_type" "management" { + physical_network_id = cloudstack_physical_network.test.id + traffic_type = "Management" + kvm_network_label = "csmgmt2" +} +` diff --git a/cloudstack/resource_cloudstack_vlan_ip_range.go b/cloudstack/resource_cloudstack_vlan_ip_range.go new file mode 100644 index 00000000..ff829fb5 --- /dev/null +++ b/cloudstack/resource_cloudstack_vlan_ip_range.go @@ -0,0 +1,295 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "fmt" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudstackVlanIpRange() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudstackVlanIpRangeCreate, + Read: resourceCloudstackVlanIpRangeRead, + Update: resourceCloudstackVlanIpRangeUpdate, + Delete: resourceCloudstackVlanIpRangeDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "account": { + Description: "account who will own the VLAN. If VLAN is Zone wide, this parameter should be omitted", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "domain_id": { + Description: "domain ID of the account owning a VLAN", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "end_ip": { + Description: "the ending IP address in the VLAN IP range", + Type: schema.TypeString, + Optional: true, + }, + "end_ipv6": { + Description: "the ending IPv6 address in the IPv6 network range", + Type: schema.TypeString, + Optional: true, + }, + "for_system_vms": { + Description: "true if IP range is set to system vms, false if not", + Type: schema.TypeBool, + Optional: true, + }, + "for_virtual_network": { + Description: "true if VLAN is of Virtual type, false if Direct", + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "gateway": { + Description: "he gateway of the VLAN IP range", + Type: schema.TypeString, + Optional: true, + }, + "ip6_cidr": { + Description: "the CIDR of IPv6 network, must be at least /64", + Type: schema.TypeString, + Optional: true, + }, + "ip6_gateway": { + Description: "the gateway of the IPv6 network. Required for Shared networks and Isolated networks when it belongs to VPC", + Type: schema.TypeString, + Optional: true, + }, + "netmask": { + Description: "the netmask of the VLAN IP range", + Type: schema.TypeString, + Optional: true, + }, + "network_id": { + Description: "the network id", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "physical_network_id": { + Description: "the physical network id", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "pod_id": { + Description: "optional parameter. Have to be specified for Direct Untagged vlan only.", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "project_id": { + Description: "project who will own the VLAN. If VLAN is Zone wide, this parameter should be omitted", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "start_ip": { + Description: "the beginning IP address in the VLAN IP range", + Type: schema.TypeString, + Optional: true, + }, + "start_ipv6": { + Description: "the beginning IPv6 address in the IPv6 network range", + Type: schema.TypeString, + Optional: true, + }, + "vlan": { + Description: "the ID or VID of the VLAN. If not specified, will be defaulted to the vlan of the network or if vlan of the network is null - to Untagged", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "zone_id": { + Description: "the Zone ID of the VLAN IP range", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudstackVlanIpRangeCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.VLAN.NewCreateVlanIpRangeParams() + if v, ok := d.GetOk("account"); ok { + p.SetAccount(v.(string)) + } + if v, ok := d.GetOk("domain_id"); ok { + p.SetDomainid(v.(string)) + } + if v, ok := d.GetOk("end_ip"); ok { + p.SetEndip(v.(string)) + } + if v, ok := d.GetOk("end_ipv6"); ok { + p.SetEndipv6(v.(string)) + } + if v, ok := d.GetOk("for_system_vms"); ok { + p.SetForsystemvms(v.(bool)) + } + if v, ok := d.GetOk("for_virtual_network"); ok { + p.SetForvirtualnetwork(v.(bool)) + } + if v, ok := d.GetOk("gateway"); ok { + p.SetGateway(v.(string)) + } + if v, ok := d.GetOk("ip6_cidr"); ok { + p.SetIp6cidr(v.(string)) + } + if v, ok := d.GetOk("ip6_gateway"); ok { + p.SetIp6gateway(v.(string)) + } + if v, ok := d.GetOk("netmask"); ok { + p.SetNetmask(v.(string)) + } + if v, ok := d.GetOk("network_id"); ok { + p.SetNetworkid(v.(string)) + } + if v, ok := d.GetOk("physical_network_id"); ok { + p.SetPhysicalnetworkid(v.(string)) + } + if v, ok := d.GetOk("pod_id"); ok { + p.SetPodid(v.(string)) + } + if v, ok := d.GetOk("project_id"); ok { + p.SetProjectid(v.(string)) + } + if v, ok := d.GetOk("start_ip"); ok { + p.SetStartip(v.(string)) + } + if v, ok := d.GetOk("start_ipv6"); ok { + p.SetStartipv6(v.(string)) + } + if v, ok := d.GetOk("vlan"); ok { + p.SetVlan(v.(string)) + } + if v, ok := d.GetOk("zone_id"); ok { + p.SetZoneid(v.(string)) + } + + // create vlan ip range + r, err := cs.VLAN.CreateVlanIpRange(p) + if err != nil { + return err + } + + d.SetId(r.Id) + + return resourceCloudstackVlanIpRangeRead(d, meta) +} + +func resourceCloudstackVlanIpRangeRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + r, _, err := cs.VLAN.GetVlanIpRangeByID(d.Id()) + if err != nil { + return err + } + + d.Set("account", r.Account) + d.Set("domain_id", r.Domainid) + d.Set("end_ip", r.Endip) + d.Set("end_ipv6", r.Endipv6) + d.Set("for_system_vms", r.Forsystemvms) + d.Set("for_virtual_network", r.Forvirtualnetwork) + d.Set("gateway", r.Gateway) + d.Set("ip6_cidr", r.Ip6cidr) + d.Set("ip6_gateway", r.Ip6gateway) + d.Set("netmask", r.Netmask) + d.Set("network_id", r.Networkid) + d.Set("physical_network_id", r.Physicalnetworkid) + d.Set("pod_id", r.Podid) + d.Set("project_id", r.Projectid) + d.Set("start_ip", r.Startip) + d.Set("start_ipv6", r.Startipv6) + d.Set("vlan", r.Vlan) + d.Set("zone_id", r.Zoneid) + + return nil +} + +func resourceCloudstackVlanIpRangeUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.VLAN.NewUpdateVlanIpRangeParams(d.Id()) + + if v, ok := d.GetOk("end_ip"); ok { + p.SetEndip(v.(string)) + } + if v, ok := d.GetOk("end_ipv6"); ok { + p.SetEndipv6(v.(string)) + } + if v, ok := d.GetOk("for_system_vms"); ok { + p.SetForsystemvms(v.(bool)) + } + if v, ok := d.GetOk("gateway"); ok { + p.SetGateway(v.(string)) + } + if v, ok := d.GetOk("ip6_cidr"); ok { + p.SetIp6cidr(v.(string)) + } + if v, ok := d.GetOk("ip6_gateway"); ok { + p.SetIp6gateway(v.(string)) + } + if v, ok := d.GetOk("netmask"); ok { + p.SetNetmask(v.(string)) + } + if v, ok := d.GetOk("start_ip"); ok { + p.SetStartip(v.(string)) + } + if v, ok := d.GetOk("start_ipv6"); ok { + p.SetStartipv6(v.(string)) + } + + // update vlaniprange + _, err := cs.VLAN.UpdateVlanIpRange(p) + if err != nil { + return err + } + + return resourceCloudstackVlanIpRangeRead(d, meta) +} + +func resourceCloudstackVlanIpRangeDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + _, err := cs.VLAN.DeleteVlanIpRange(cs.VLAN.NewDeleteVlanIpRangeParams(d.Id())) + if err != nil { + return fmt.Errorf("Error deleting Vlan Ip Range: %s", err) + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_vlan_ip_range_test.go b/cloudstack/resource_cloudstack_vlan_ip_range_test.go new file mode 100644 index 00000000..b8c3885c --- /dev/null +++ b/cloudstack/resource_cloudstack_vlan_ip_range_test.go @@ -0,0 +1,114 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudstackVlanIpRange_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudstackVlanIpRange_basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "gateway", "10.0.0.1"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "netmask", "255.255.255.0"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "start_ip", "10.0.0.2"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "end_ip", "10.0.0.10"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "vlan", "vlan://123"), + ), + }, + { + Config: testAccCloudstackVlanIpRange_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "gateway", "10.0.0.1"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "netmask", "255.255.255.0"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "start_ip", "10.0.0.2"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "end_ip", "10.0.0.20"), + resource.TestCheckResourceAttr("cloudstack_vlan_ip_range.test", "vlan", "vlan://123"), + ), + }, + }, + }) +} + +const testAccCloudstackVlanIpRange_basic = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_vlan_ip_range" "test" { + physical_network_id = cloudstack_physical_network.test.id + for_virtual_network = true + zone_id = cloudstack_zone.test.id + gateway = "10.0.0.1" + netmask = "255.255.255.0" + start_ip = "10.0.0.2" + end_ip = "10.0.0.10" + vlan = "vlan://123" +} +` +const testAccCloudstackVlanIpRange_update = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_vlan_ip_range" "test" { + physical_network_id = cloudstack_physical_network.test.id + for_virtual_network = true + zone_id = cloudstack_zone.test.id + gateway = "10.0.0.1" + netmask = "255.255.255.0" + start_ip = "10.0.0.2" + end_ip = "10.0.0.20" + vlan = "vlan://123" +} +` diff --git a/cloudstack/resource_cloudstack_zone.go b/cloudstack/resource_cloudstack_zone.go index d7433df9..4e568608 100644 --- a/cloudstack/resource_cloudstack_zone.go +++ b/cloudstack/resource_cloudstack_zone.go @@ -21,7 +21,6 @@ package cloudstack import ( "fmt" - "log" "github.com/apache/cloudstack-go/v2/cloudstack" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -33,22 +32,91 @@ func resourceCloudStackZone() *schema.Resource { Read: resourceCloudStackZoneRead, Update: resourceCloudStackZoneUpdate, Delete: resourceCloudStackZoneDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, + "allocation_state": { + Description: "Allocation state of this Zone for allocation of new resources", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "dhcp_provider": { + Description: "the dhcp Provider for the Zone", + Type: schema.TypeString, + Optional: true, + Computed: true, }, "dns1": { - Type: schema.TypeString, - Required: true, + Description: "the first DNS for the Zone", + Type: schema.TypeString, + Required: true, + }, + "dns2": { + Description: "the second DNS for the Zone", + Type: schema.TypeString, + Optional: true, + }, + "domain": { + Description: "Network domain name for the networks in the zone", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "domain_id": { + Description: "the ID of the containing domain, null for public zones", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "guest_cidr_address": { + Description: "the guest CIDR address for the Zone", + Type: schema.TypeString, + Optional: true, }, "internal_dns1": { - Type: schema.TypeString, - Required: true, + Description: "the first internal DNS for the Zone", + Type: schema.TypeString, + Required: true, + }, + "internal_dns2": { + Description: "the second internal DNS for the Zone", + Type: schema.TypeString, + Optional: true, + }, + "ip6_dns1": { + Description: "the first DNS for IPv6 network in the Zone", + Type: schema.TypeString, + Optional: true, + }, + "ip6_dns2": { + Description: "the second DNS for IPv6 network in the Zone", + Type: schema.TypeString, + Optional: true, + }, + "local_storage_enabled": { + Description: "true if local storage offering enabled, false otherwise", + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "name": { + Description: "the name of the Zone", + Type: schema.TypeString, + Required: true, }, "network_type": { - Type: schema.TypeString, - Required: true, + Description: "network type of the zone, can be Basic or Advanced", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "security_group_enabled": { + Description: "true if network is security group enabled, false otherwise", + Type: schema.TypeBool, + Optional: true, + ForceNew: true, }, }, } @@ -56,61 +124,131 @@ func resourceCloudStackZone() *schema.Resource { func resourceCloudStackZoneCreate(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) - name := d.Get("name").(string) - dns1 := d.Get("dns1").(string) - internal_dns1 := d.Get("internal_dns1").(string) - network_type := d.Get("network_type").(string) - - // Create a new parameter struct - p := cs.Zone.NewCreateZoneParams(dns1, internal_dns1, name, network_type) - log.Printf("[DEBUG] Creating Zone %s", name) - n, err := cs.Zone.CreateZone(p) + p := cs.Zone.NewCreateZoneParams(d.Get("dns1").(string), d.Get("internal_dns1").(string), d.Get("name").(string), d.Get("network_type").(string)) + if v, ok := d.GetOk("allocation_state"); ok { + p.SetAllocationstate(v.(string)) + } + if v, ok := d.GetOk("dns2"); ok { + p.SetDns2(v.(string)) + } + if v, ok := d.GetOk("domain"); ok { + p.SetDomain(v.(string)) + } + if v, ok := d.GetOk("domain_id"); ok { + p.SetDomainid(v.(string)) + } + if v, ok := d.GetOk("guest_cidr_address"); ok { + p.SetGuestcidraddress(v.(string)) + } + if v, ok := d.GetOk("internal_dns2"); ok { + p.SetInternaldns2(v.(string)) + } + if v, ok := d.GetOk("ip6_dns1"); ok { + p.SetIp6dns1(v.(string)) + } + if v, ok := d.GetOk("ip6_dns2"); ok { + p.SetIp6dns2(v.(string)) + } + if v, ok := d.GetOk("local_storage_enabled"); ok { + p.SetLocalstorageenabled(v.(bool)) + } + if v, ok := d.GetOk("security_group_enabled"); ok { + p.SetSecuritygroupenabled(v.(bool)) + } + // Create zone + r, err := cs.Zone.CreateZone(p) if err != nil { return err } - log.Printf("[DEBUG] Zone %s successfully created", name) - d.SetId(n.Id) + d.SetId(r.Id) return resourceCloudStackZoneRead(d, meta) } func resourceCloudStackZoneRead(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) - log.Printf("[DEBUG] Retrieving Zone %s", d.Get("name").(string)) - - // Get the Zone details - z, count, err := cs.Zone.GetZoneByName(d.Get("name").(string)) + z, _, err := cs.Zone.GetZoneByID(d.Id()) if err != nil { - if count == 0 { - log.Printf("[DEBUG] Zone %s does no longer exist", d.Get("name").(string)) - d.SetId("") - return nil - } return err } - d.SetId(z.Id) - d.Set("name", z.Name) + d.Set("allocation_state", z.Allocationstate) + d.Set("dhcp_provider", z.Dhcpprovider) d.Set("dns1", z.Dns1) + d.Set("dns2", z.Dns2) + d.Set("domain", z.Domain) + d.Set("domain_id", z.Domainid) + d.Set("guest_cidr_address", z.Guestcidraddress) d.Set("internal_dns1", z.Internaldns1) + d.Set("internal_dns2", z.Internaldns2) + d.Set("ip6_dns1", z.Ip6dns1) + d.Set("ip6_dns2", z.Ip6dns2) + d.Set("local_storage_enabled", z.Localstorageenabled) + d.Set("name", z.Name) d.Set("network_type", z.Networktype) + d.Set("security_group_enabled", z.Securitygroupsenabled) return nil } -func resourceCloudStackZoneUpdate(d *schema.ResourceData, meta interface{}) error { return nil } +func resourceCloudStackZoneUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.Zone.NewUpdateZoneParams(d.Id()) + if v, ok := d.GetOk("allocation_state"); ok { + p.SetAllocationstate(v.(string)) + } + if v, ok := d.GetOk("dhcp_provider"); ok { + p.SetDhcpprovider(v.(string)) + } + if v, ok := d.GetOk("dns1"); ok { + p.SetDns1(v.(string)) + } + if v, ok := d.GetOk("dns2"); ok { + p.SetDns2(v.(string)) + } + if v, ok := d.GetOk("domain"); ok { + p.SetDomain(v.(string)) + } + if v, ok := d.GetOk("guest_cidr_address"); ok { + p.SetGuestcidraddress(v.(string)) + } + if v, ok := d.GetOk("internal_dns1"); ok { + p.SetInternaldns1(v.(string)) + } + if v, ok := d.GetOk("internal_dns2"); ok { + p.SetInternaldns2(v.(string)) + } + if v, ok := d.GetOk("ip6_dns1"); ok { + p.SetIp6dns1(v.(string)) + } + if v, ok := d.GetOk("ip6_dns2"); ok { + p.SetIp6dns2(v.(string)) + } + if v, ok := d.GetOk("local_storage_enabled"); ok { + p.SetLocalstorageenabled(v.(bool)) + } + if v, ok := d.GetOk("name"); ok { + p.SetName(v.(string)) + } + + _, err := cs.Zone.UpdateZone(p) + if err != nil { + return err + } + + return resourceCloudStackZoneRead(d, meta) +} func resourceCloudStackZoneDelete(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) - // Create a new parameter struct - p := cs.Zone.NewDeleteZoneParams(d.Id()) - _, err := cs.Zone.DeleteZone(p) - + // Delete zone + _, err := cs.Zone.DeleteZone(cs.Zone.NewDeleteZoneParams(d.Id())) if err != nil { return fmt.Errorf("Error deleting Zone: %s", err) } diff --git a/cloudstack/resource_cloudstack_zone_test.go b/cloudstack/resource_cloudstack_zone_test.go new file mode 100644 index 00000000..d38f27a6 --- /dev/null +++ b/cloudstack/resource_cloudstack_zone_test.go @@ -0,0 +1,69 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package cloudstack + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudStackZone_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackZone_basic, + }, + { + Config: testAccCloudStackZone_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cloudstack_zone.test", "name", "acctestupdated"), + ), + }, + }, + }) +} + +const testAccCloudStackZone_basic = ` +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +` + +const testAccCloudStackZone_update = ` +resource "cloudstack_zone" "test" { + name = "acctestupdated" + dns1 = "8.8.4.4" + dns2 = "8.8.4.4" + internal_dns1 = "8.8.8.8" + internal_dns2 = "8.8.8.8" + network_type = "Advanced" + domain = "cloudstack.apache.org" + guest_cidr_address = "172.29.2.0/20" +} +` diff --git a/go.mod b/go.mod index 8952c350..66a6c4e3 100644 --- a/go.mod +++ b/go.mod @@ -68,4 +68,4 @@ require ( go 1.21 -toolchain go1.21.6 +toolchain go1.21.6 \ No newline at end of file diff --git a/go.sum b/go.sum index 51980c36..91e5a04d 100644 --- a/go.sum +++ b/go.sum @@ -241,4 +241,4 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/website/docs/r/cluster.html.markdown b/website/docs/r/cluster.html.markdown new file mode 100644 index 00000000..c5da1946 --- /dev/null +++ b/website/docs/r/cluster.html.markdown @@ -0,0 +1,67 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_cluster" +sidebar_current: "docs-cloudstack-resource-cluster" +description: |- + Adds a new cluster +--- + +# cloudstack_cluster + +Adds a new cluster + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_cluster" "example" { + cluster_name = "example" + cluster_type = "CloudManaged" + hypervisor = "KVM" + pod_id = cloudstack_pod.example.id + zone_id = cloudstack_zone.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `allocation_state` - (Optional) Allocation state of this cluster for allocation of new resources. +* `cluster_name` - (Required) the cluster name. +* `cluster_type` - (Required) type of the cluster: CloudManaged, ExternalManaged. +* `guest_vswitch_name` - (Optional) Name of virtual switch used for guest traffic in the cluster. This would override zone wide traffic label setting.. +* `guest_vswitch_type` - (Optional) Type of virtual switch used for guest traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch). +* `hypervisor` - (Required) hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator,Ovm3. +* `ovm3_cluster` - (Optional) Ovm3 native OCFS2 clustering enabled for cluster. +* `ovm3_pool` - (Optional) Ovm3 native pooling enabled for cluster. +* `ovm3_vip` - (Optional) Ovm3 vip to use for pool (and cluster). +* `password` - (Optional) the password for the host. +* `public_vswitch_name` - (Optional) Name of virtual switch used for public traffic in the cluster. This would override zone wide traffic label setting.. +* `public_vswitch_type` - (Optional) Type of virtual switch used for public traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch). +* `pod_id` - (Required) the Pod ID for the host. +* `url` - (Optional) the URL. +* `username` - (Optional) the username for the cluster. +* `vsm_ip_address` - (Optional) the ipaddress of the VSM associated with this cluster. +* `vsm_password` - (Optional) the password for the VSM associated with this cluster. +* `vsm_username` - (Optional) the username for the VSM associated with this cluster. +* `zone_id` - (Required) the Zone ID for the cluster. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The instance ID. + + + +## Import + +Clusters can be imported; use `` as the import ID. For +example: + +```shell +terraform import cloudstack_cluster.example 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +``` diff --git a/website/docs/r/network_service_provider_state.html.markdown b/website/docs/r/network_service_provider_state.html.markdown new file mode 100644 index 00000000..cd0d77d0 --- /dev/null +++ b/website/docs/r/network_service_provider_state.html.markdown @@ -0,0 +1,80 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_network_service_provider_state" +sidebar_current: "docs-cloudstack-resource-network_service_provider_state" +description: |- + Manage network service providers for a given physical network. +--- + +# cloudstack_zone + +Manage network service providers for a given physical network. If Service Provider includes an underlying `Element` (configureInternalLoadBalancerElement, configureVirtualRouterElement) it will be configured. + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_network_service_provider_state" "virtualrouter" { + name = "VirtualRouter" + physical_network_id = cloudstack_physical_network.test.id + enabled = true +} +resource "cloudstack_network_service_provider_state" "vpcvirtualrouter" { + name = "VpcVirtualRouter" + physical_network_id = cloudstack_physical_network.test.id + enabled = true +} +resource "cloudstack_network_service_provider_state" "internallbvm" { + name = "InternalLbVm" + physical_network_id = cloudstack_physical_network.test.id + enabled = false +} +resource "cloudstack_network_service_provider_state" "configdrive" { + name = "ConfigDrive" + physical_network_id = cloudstack_physical_network.test.id + enabled = false +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) account who will own the VLAN. If VLAN is Zone wide, this parameter should be omitted +* `physical_network_id` - (Required) domain ID of the account owning a VLAN +* `enabled` - (Required) the ending IP address in the VLAN IP range + + +## Attributes Reference + +The following attributes are exported: + +* `id` - uuid of the network provider + + +## Import + +Network service providers can be imported; use `` as the import ID. For +example: + +```shell +terraform import cloudstack_network_service_provider_state.example VirtualRouter 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +``` diff --git a/website/docs/r/physical_network.html.markdown b/website/docs/r/physical_network.html.markdown new file mode 100644 index 00000000..3715ed24 --- /dev/null +++ b/website/docs/r/physical_network.html.markdown @@ -0,0 +1,56 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: physical_network" +sidebar_current: "docs-cloudstack-resource-physical-network" +description: |- + Creates a physical network +--- + +# physical_network + +Creates a physical network + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_physical_network" "example" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "example" + network_speed = "10G" + tags = "vlan" + zone_id = cloudstack_zone.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `broadcast_domain_range` - (Optional) changeme. +* `domain_id` - (Optional) changeme. +* `isolation_methods` - (Optional) changeme. +* `name` - (Required) changeme. +* `network_speed` - (Optional) changeme. +* `tags` - (Optional) changeme. +* `vlan` - (Optional) changeme. +* `zone_id` - (Required) changeme. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The instance ID. + + +## Import + +Physical networks can be imported; use `` as the import ID. For +example: + +```shell +terraform import physical_network.example 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +``` diff --git a/website/docs/r/pod.html.markdown b/website/docs/r/pod.html.markdown new file mode 100644 index 00000000..412ef1d5 --- /dev/null +++ b/website/docs/r/pod.html.markdown @@ -0,0 +1,56 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_pod" +sidebar_current: "docs-cloudstack-resource-pod" +description: |- + Creates a new Pod. +--- + +# cloudstack_pod + +Creates a new Pod. + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_pod" "example" { + allocation_state = "Disabled" + gateway = "172.29.0.1" + name = "example" + netmask = "255.255.240.0" + start_ip = "172.29.0.2" + zone_id = cloudstack_zone.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `allocation_state` - (Optional) allocation state of this Pod for allocation of new resources. +* `end_ip` - (Optional) the ending IP address for the Pod. +* `gateway` - (Required) the gateway for the Pod. +* `name` - (Required) the name of the Pod. +* `netmask` - (Required) the netmask for the Pod. +* `start_ip` - (Required) the starting IP address for the Pod. +* `zone_id` - (Required) the Zone ID in which the Pod will be created. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The instance ID. + + + +## Import + +A pod can be imported; use `` as the import ID. For +example: + +```shell +terraform import cloudstack_pod.example 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +``` diff --git a/website/docs/r/secondary_storage.html.markdown b/website/docs/r/secondary_storage.html.markdown new file mode 100644 index 00000000..eb839adf --- /dev/null +++ b/website/docs/r/secondary_storage.html.markdown @@ -0,0 +1,51 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_secondary_storage" +sidebar_current: "docs-cloudstack-resource-secondary-storage" +description: |- + Creates a changeme. +--- + +# cloudstack_secondary_storage + +Create secondary storage + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_secondary_storage" "example" { + name = "example" + storage_provider = "NFS" + url = "nfs://10.147.28.6:/export/home/sandbox/secondary" + zone_id = data.cloudstack_zone.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Optional) the name for the image store. +* `storage_provider` - (Required) the image store provider name. +* `url` - (Optional) the URL for the image store. +* `zone_id` - (Optional) the Zone ID for the image store. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The instance ID. + + + +## Import + +changeme can be imported; use `` as the import ID. For +example: + +```shell +terraform import cloudstack_secondary_storage.example 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +``` diff --git a/website/docs/r/storage_pool.html.markdown b/website/docs/r/storage_pool.html.markdown new file mode 100644 index 00000000..132242e5 --- /dev/null +++ b/website/docs/r/storage_pool.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_storage_pool" +sidebar_current: "docs-cloudstack-resource-storage-pool" +description: |- + Creates a storage pool. +--- + +# cloudstack_storage_pool + +Creates a storage pool. + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_storage_pool" "example" { + name = "example" + url = "nfs://10.147.28.6/export/home/sandbox/primary11" + zone_id = "0ed38eb3-f279-4951-ac20-fef39ebab20c" + cluster_id = "9daeeb36-d8b7-497a-9b53-bbebba88c817" + pod_id = "2ff52b73-139e-4c40-a0a3-5b7d87d8e3c4" + scope = "CLUSTER" + hypervisor = "Simulator" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `cluster_id` - (Optional) the cluster ID for the storage pool. +* `hypervisor` - (Optional) hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now. +* `name` - (Required) the name for the storage pool. +* `pod_id` - (Optional) the Pod ID for the storage pool. +* `storage_provider` - (Optional) the storage provider name. +* `scope` - (Optional) the scope of the storage: cluster or zone. +* `state` - (Optional) the state of the storage pool. +* `tags` - (Optional) the tags for the storage pool. +* `url` - (Required) the URL of the storage pool. +* `zone_id` - (Required) the Zone ID for the storage pool. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The instance ID. + + + +## Import + +Storage pools can be imported; use `` as the import ID. For +example: + +```shell +terraform import cloudstack_storage_pool.example 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +``` diff --git a/website/docs/r/traffic_type.html.markdown b/website/docs/r/traffic_type.html.markdown new file mode 100644 index 00000000..a3024ac4 --- /dev/null +++ b/website/docs/r/traffic_type.html.markdown @@ -0,0 +1,45 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_traffic_type" +sidebar_current: "docs-cloudstack-resource-traffic-type" +description: |- + Adds traffic type to a physical network. +--- + +# cloudstack_traffic_type + +Adds traffic type to a physical network. + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_traffic_type" "example" { + physical_network_id = cloudstack_physical_network.example.id + traffic_type = "Management" + kvm_network_label = "example" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `hyperv_network_label` - (Optional) The network name label of the physical device dedicated to this traffic on a Hyperv host. +* `isolation_method` - (Optional) Used if physical network has multiple isolation types and traffic type is public. Choose which isolation method. Valid options currently 'vlan' or 'vxlan', defaults to 'vlan'.. +* `kvm_network_label` - (Optional) The network name label of the physical device dedicated to this traffic on a KVM host. +* `ovm3_network_label` - (Optional) The network name of the physical device dedicated to this traffic on an OVM3 host. +* `physical_network_id` - (Required) The Physical Network ID. +* `traffic_type` - (Required) The trafficType to be added to the physical network. +* `vlan` - (Optional) The VLAN id to be used for Management traffic by VMware host. +* `vmware_network_label` - (Optional) The network name label of the physical device dedicated to this traffic on a VMware host. +* `xen_network_label` - (Optional) The network name label of the physical device dedicated to this traffic on a XenServer host. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The instance ID. + diff --git a/website/docs/r/vlan_ip_range.html.markdown b/website/docs/r/vlan_ip_range.html.markdown new file mode 100644 index 00000000..8292610c --- /dev/null +++ b/website/docs/r/vlan_ip_range.html.markdown @@ -0,0 +1,86 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_vlan_ip_range" +sidebar_current: "docs-cloudstack-resource-vlan_ip_range" +description: |- + Creates a VLAN IP range. +--- + +# cloudstack_zone + +Creates a VLAN IP range. + +## Example Usage + +Basic usage: + +```hcl +resource "cloudstack_zone" "test" { + name = "acctest" + dns1 = "8.8.8.8" + dns2 = "8.8.8.8" + internal_dns1 = "8.8.4.4" + internal_dns2 = "8.8.4.4" + network_type = "Advanced" + domain = "cloudstack.apache.org" +} +resource "cloudstack_physical_network" "test" { + broadcast_domain_range = "ZONE" + isolation_methods = "VLAN" + name = "test01" + network_speed = "1G" + tags = "vlan" + zone_id = cloudstack_zone.test.id +} +resource "cloudstack_vlan_ip_range" "test" { + physical_network_id = cloudstack_physical_network.test.id + for_virtual_network = true + zone_id = cloudstack_zone.test.id + gateway = "10.0.0.1" + netmask = "255.255.255.0" + start_ip = "10.0.0.2" + end_ip = "10.0.0.10" + vlan = "vlan://123" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `account` - (Optional) account who will own the VLAN. If VLAN is Zone wide, this parameter should be omitted +* `domain_id` - (Optional) domain ID of the account owning a VLAN +* `end_ip` - (Optional) the ending IP address in the VLAN IP range +* `end_ipv6` - (Optional) the ending IPv6 address in the IPv6 network range +* `for_system_vms` - (Optional) true if IP range is set to system vms, false if not +* `for_virtual_network` - (Optional) true if VLAN is of Virtual type, false if Direct +* `gateway` - (Optional) the gateway of the VLAN IP range +* `ip6_cidr` - (Optional) the CIDR of IPv6 network, must be at least /64 +* `ip6_gateway` - (Optional) the gateway of the IPv6 network. Required for Shared networks and Isolated networks when it belongs to VPC +* `netmask` - (Optional) the netmask of the VLAN IP range +* `network_id` - (Optional) the network id +* `physical_network_id` - (Optional) the physical network id +* `pod_id` - (Optional) Have to be specified for Direct Untagged vlan only. +* `project_id` - (Optional) project who will own the VLAN. If VLAN is Zone wide, this parameter should be omitted +* `start_ip` - (Optional) the beginning IP address in the VLAN IP range +* `start_ipv6` - (Optional) the beginning IPv6 address in the IPv6 network range +* `vlan` - (Optional) true if network is security group enabled, false otherwise +* `start_ipv6` - (Optional) the ID or VID of the VLAN. If not specified, will be defaulted to the vlan of the network or if vlan of the network is null - to Untagged +* `zone_id` - (Optional) the Zone ID of the VLAN IP range + +## Attributes Reference + +The following attributes are exported: + +* `id` - the ID of the VLAN IP range +* `network_id` - the network id of vlan range + + +## Import + +Vlan ip range can be imported; use `` as the import ID. For +example: + +```shell +terraform import cloudstack_vlan_ip_range.example 5cf69677-7e4b-4bf4-b868-f0b02bb72ee0 +```