diff --git a/docs/data-sources/floatingip.md b/docs/data-sources/floatingip.md index 91ae492b..0329c76d 100644 --- a/docs/data-sources/floatingip.md +++ b/docs/data-sources/floatingip.md @@ -71,5 +71,3 @@ Read-Only: - `key` (String) - `read_only` (Boolean) - `value` (String) - - diff --git a/docs/data-sources/image.md b/docs/data-sources/image.md index f2d62cfb..9168398d 100644 --- a/docs/data-sources/image.md +++ b/docs/data-sources/image.md @@ -71,5 +71,3 @@ Read-Only: - `key` (String) - `read_only` (Boolean) - `value` (String) - - diff --git a/docs/data-sources/instance.md b/docs/data-sources/instance.md index 88214e8c..40b153b3 100644 --- a/docs/data-sources/instance.md +++ b/docs/data-sources/instance.md @@ -116,5 +116,3 @@ Read-Only: - `delete_on_termination` (Boolean) - `volume_id` (String) - - diff --git a/docs/data-sources/k8s.md b/docs/data-sources/k8s.md index 52a56586..0e01f69c 100644 --- a/docs/data-sources/k8s.md +++ b/docs/data-sources/k8s.md @@ -82,5 +82,3 @@ Read-Only: - `node_count` (Number) - `stack_id` (String) - `uuid` (String) - - diff --git a/docs/data-sources/k8s_client_config.md b/docs/data-sources/k8s_client_config.md index 8ddf6775..ed26b094 100644 --- a/docs/data-sources/k8s_client_config.md +++ b/docs/data-sources/k8s_client_config.md @@ -43,5 +43,3 @@ data "edgecenter_k8s_client_config" "cfg" { - `client_certificate_data` (String) The client_certificate_data field from k8s config. - `client_key_data` (String) The client_key_data field from k8s config. - `id` (String) The ID of this resource. - - diff --git a/docs/data-sources/k8s_pool.md b/docs/data-sources/k8s_pool.md index fa0f111b..0be95f9e 100644 --- a/docs/data-sources/k8s_pool.md +++ b/docs/data-sources/k8s_pool.md @@ -55,5 +55,3 @@ data "edgecenter_k8s_pool" "pool" { - `node_count` (Number) The current number of nodes in the pool. - `node_names` (List of String) A list of names of nodes within the pool. - `stack_id` (String) The identifier of the underlying infrastructure stack used by this pool. - - diff --git a/docs/data-sources/lblistener.md b/docs/data-sources/lblistener.md index b58b1fe2..2bd9a88a 100644 --- a/docs/data-sources/lblistener.md +++ b/docs/data-sources/lblistener.md @@ -61,5 +61,3 @@ output "view" { - `protocol` (String) Available values is 'HTTP', 'HTTPS', 'TCP', 'UDP' - `protocol_port` (Number) The port on which the protocol is bound. - `provisioning_status` (String) The current provisioning status of the load balancer. - - diff --git a/docs/data-sources/lbpool.md b/docs/data-sources/lbpool.md index 3c0bc40d..91398b9b 100644 --- a/docs/data-sources/lbpool.md +++ b/docs/data-sources/lbpool.md @@ -87,5 +87,3 @@ Read-Only: - `persistence_granularity` (String) - `persistence_timeout` (Number) - `type` (String) - - diff --git a/docs/data-sources/loadbalancer.md b/docs/data-sources/loadbalancer.md index dc6a47f9..bc5d0be3 100644 --- a/docs/data-sources/loadbalancer.md +++ b/docs/data-sources/loadbalancer.md @@ -79,5 +79,3 @@ Read-Only: - `key` (String) - `read_only` (Boolean) - `value` (String) - - diff --git a/docs/data-sources/loadbalancerv2.md b/docs/data-sources/loadbalancerv2.md index 80488550..f600b504 100644 --- a/docs/data-sources/loadbalancerv2.md +++ b/docs/data-sources/loadbalancerv2.md @@ -67,5 +67,3 @@ Read-Only: - `key` (String) - `read_only` (Boolean) - `value` (String) - - diff --git a/docs/data-sources/network.md b/docs/data-sources/network.md index 29133f02..655b4a02 100644 --- a/docs/data-sources/network.md +++ b/docs/data-sources/network.md @@ -96,5 +96,3 @@ Read-Only: - `destination` (String) - `nexthop` (String) - - diff --git a/docs/data-sources/project.md b/docs/data-sources/project.md index e267efb9..514371f4 100644 --- a/docs/data-sources/project.md +++ b/docs/data-sources/project.md @@ -32,5 +32,3 @@ data "edgecenter_project" "pr" { ### Read-Only - `id` (String) The ID of this resource. - - diff --git a/docs/data-sources/region.md b/docs/data-sources/region.md index 0351bff3..63c21ed2 100644 --- a/docs/data-sources/region.md +++ b/docs/data-sources/region.md @@ -32,5 +32,3 @@ data "edgecenter_region" "rg" { ### Read-Only - `id` (String) The ID of this resource. - - diff --git a/docs/data-sources/reservedfixedip.md b/docs/data-sources/reservedfixedip.md index 9edae5a4..2f709163 100644 --- a/docs/data-sources/reservedfixedip.md +++ b/docs/data-sources/reservedfixedip.md @@ -67,5 +67,3 @@ Read-Only: - `ip_address` (String) - `mac_address` (String) - - diff --git a/docs/data-sources/router.md b/docs/data-sources/router.md index 43a0572e..6eb92ec9 100644 --- a/docs/data-sources/router.md +++ b/docs/data-sources/router.md @@ -97,5 +97,3 @@ Read-Only: - `destination` (String) - `nexthop` (String) - - diff --git a/docs/data-sources/secret.md b/docs/data-sources/secret.md index 4ee24d2e..961266f4 100644 --- a/docs/data-sources/secret.md +++ b/docs/data-sources/secret.md @@ -60,5 +60,3 @@ output "view" { - `id` (String) The ID of this resource. - `mode` (String) The mode of the encryption algorithm. - `status` (String) The current status of the secret. - - diff --git a/docs/data-sources/securitygroup.md b/docs/data-sources/securitygroup.md index 75610362..b485c147 100644 --- a/docs/data-sources/securitygroup.md +++ b/docs/data-sources/securitygroup.md @@ -84,5 +84,3 @@ Read-Only: - `protocol` (String) - `remote_ip_prefix` (String) - `updated_at` (String) - - diff --git a/docs/data-sources/servergroup.md b/docs/data-sources/servergroup.md index 4cbc4651..2deb5596 100644 --- a/docs/data-sources/servergroup.md +++ b/docs/data-sources/servergroup.md @@ -63,5 +63,3 @@ Read-Only: - `instance_id` (String) - `instance_name` (String) - - diff --git a/docs/data-sources/storage_s3.md b/docs/data-sources/storage_s3.md index 8e726c4a..5a545c12 100644 --- a/docs/data-sources/storage_s3.md +++ b/docs/data-sources/storage_s3.md @@ -38,5 +38,3 @@ data "edgecenter_storage_s3" "example_s3" { - `generated_s3_endpoint` (String) A s3 endpoint for new storage resource. - `id` (String) The ID of this resource. - `location` (String) A location of new storage resource. One of (s-dt2) - - diff --git a/docs/data-sources/storage_s3_bucket.md b/docs/data-sources/storage_s3_bucket.md index 08223c02..abf8402d 100644 --- a/docs/data-sources/storage_s3_bucket.md +++ b/docs/data-sources/storage_s3_bucket.md @@ -34,5 +34,3 @@ data "edgecenter_storage_s3_bucket" "example_s3_bucket" { ### Read-Only - `id` (String) The ID of this resource. - - diff --git a/docs/data-sources/subnet.md b/docs/data-sources/subnet.md index b7444fe3..12f2d7ce 100644 --- a/docs/data-sources/subnet.md +++ b/docs/data-sources/subnet.md @@ -81,5 +81,3 @@ Read-Only: - `key` (String) - `read_only` (Boolean) - `value` (String) - - diff --git a/docs/data-sources/volume.md b/docs/data-sources/volume.md index aa99d73f..bee7327d 100644 --- a/docs/data-sources/volume.md +++ b/docs/data-sources/volume.md @@ -69,5 +69,3 @@ Read-Only: - `key` (String) - `read_only` (Boolean) - `value` (String) - - diff --git a/docs/resources/cdn_origingroup.md b/docs/resources/cdn_origingroup.md index 17853aed..a49a6715 100644 --- a/docs/resources/cdn_origingroup.md +++ b/docs/resources/cdn_origingroup.md @@ -60,5 +60,3 @@ Optional: Read-Only: - `id` (Number) The ID of this resource. - - diff --git a/docs/resources/cdn_resource.md b/docs/resources/cdn_resource.md index 9ca6c652..6e0cc886 100644 --- a/docs/resources/cdn_resource.md +++ b/docs/resources/cdn_resource.md @@ -618,5 +618,3 @@ Required: Optional: - `enabled` (Boolean) - - diff --git a/docs/resources/cdn_rule.md b/docs/resources/cdn_rule.md index 3c1422bc..d4692f62 100644 --- a/docs/resources/cdn_rule.md +++ b/docs/resources/cdn_rule.md @@ -607,5 +607,3 @@ Required: Optional: - `enabled` (Boolean) - - diff --git a/docs/resources/cdn_sslcert.md b/docs/resources/cdn_sslcert.md index 0b909e6e..7910c836 100644 --- a/docs/resources/cdn_sslcert.md +++ b/docs/resources/cdn_sslcert.md @@ -48,5 +48,3 @@ resource "edgecenter_cdn_sslcert" "cdnopt_cert" { - `automated` (Boolean) The way SSL certificate was issued. - `has_related_resources` (Boolean) It shows if the SSL certificate is used by a CDN resource. - `id` (String) The ID of this resource. - - diff --git a/docs/resources/instance.md b/docs/resources/instance.md index b7b4dc9a..78c74f9e 100644 --- a/docs/resources/instance.md +++ b/docs/resources/instance.md @@ -75,10 +75,11 @@ resource "edgecenter_instance" "instance" { } interface { - type = "subnet" - network_id = edgecenter_network.network.id - subnet_id = edgecenter_subnet.subnet.id - security_groups = ["d75db0b2-58f1-4a11-88c6-a932bb897310"] + type = "subnet" + network_id = edgecenter_network.network.id + subnet_id = edgecenter_subnet.subnet.id + security_groups = ["d75db0b2-58f1-4a11-88c6-a932bb897310"] + port_security_disabled = true } metadata_map = { @@ -199,6 +200,7 @@ Optional: - `network_id` (String) Required if type is 'subnet' or 'any_subnet'. - `order` (Number) Order of attaching interface - `port_id` (String) required if type is 'reserved_fixed_ip' +- `port_security_disabled` (Boolean) - `security_groups` (List of String) list of security group IDs - `subnet_id` (String) Required if type is 'subnet'. - `type` (String) Available value is 'subnet', 'any_subnet', 'external', 'reserved_fixed_ip' diff --git a/docs/resources/keypair.md b/docs/resources/keypair.md index 74519a64..e38fb751 100644 --- a/docs/resources/keypair.md +++ b/docs/resources/keypair.md @@ -46,5 +46,3 @@ output "kp" { - `fingerprint` (String) A fingerprint of the SSH public key, used to verify the integrity of the key. - `id` (String) The ID of this resource. - `sshkey_id` (String) The unique identifier assigned by the provider to the SSH key pair. - - diff --git a/docs/resources/storage_s3.md b/docs/resources/storage_s3.md index 31a9e86d..48bd7436 100644 --- a/docs/resources/storage_s3.md +++ b/docs/resources/storage_s3.md @@ -44,5 +44,3 @@ resource "edgecenter_storage_s3" "example_s3" { ### Read-Only - `id` (String) The ID of this resource. - - diff --git a/docs/resources/storage_s3_bucket.md b/docs/resources/storage_s3_bucket.md index 436760c2..cc354c7a 100644 --- a/docs/resources/storage_s3_bucket.md +++ b/docs/resources/storage_s3_bucket.md @@ -34,5 +34,3 @@ resource "edgecenter_storage_s3_bucket" "example_s3_bucket" { ### Read-Only - `id` (String) The ID of this resource. - - diff --git a/edgecenter/resource_edgecenter_instance.go b/edgecenter/resource_edgecenter_instance.go index 31142501..ab1635b0 100644 --- a/edgecenter/resource_edgecenter_instance.go +++ b/edgecenter/resource_edgecenter_instance.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "fmt" + "github.com/Edge-Center/edgecentercloud-go/edgecenter/port/v1/ports" "log" "sort" "strconv" @@ -28,6 +29,7 @@ const ( InstanceDeleting int = 1200 InstanceCreatingTimeout int = 1200 InstancePoint = "instances" + PortsPoint = "ports" InstanceVMStateActive = "active" InstanceVMStateStopped = "stopped" @@ -223,6 +225,11 @@ func resourceInstance() *schema.Resource { Computed: true, Optional: true, }, + "port_security_disabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, }, }, }, @@ -498,6 +505,62 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter return Instance, nil }, ) + if err != nil { + return diag.FromErr(err) + } + instanceID := InstanceID.(string) + interfacesListAPI, err := instances.ListInterfacesAll(clientV1, instanceID) + if err != nil { + return diag.FromErr(err) + } + + portSecurityOptsListExtracted, err := extractPortSecurityOpts(ifs) + if err != nil { + return diag.FromErr(err) + } + + var portSecurityOptsList []InstancePortSecurityOpts + for _, iFace := range interfacesListAPI { + if len(iFace.IPAssignments) == 0 { + continue + } + + portID := iFace.PortID + for _, assignment := range iFace.IPAssignments { + + subnetID := assignment.SubnetID + ipAddress := assignment.IPAddress.String() + + var portSecurityDisabled bool + for _, interfaceExtracted := range portSecurityOptsListExtracted { + if interfaceExtracted.SubnetID == subnetID || interfaceExtracted.IPAddress == ipAddress || interfaceExtracted.PortID == portID { + portSecurityDisabled = interfaceExtracted.PortSecurityDisabled + break + } + } + + var portSecOpts InstancePortSecurityOpts + portSecOpts.PortID = portID + portSecOpts.PortSecurityDisabled = portSecurityDisabled + + portSecurityOptsList = append(portSecurityOptsList, portSecOpts) + } + } + + if len(portSecurityOptsList) > 0 { + portsClientV1, err := CreateClient(provider, d, PortsPoint, VersionPointV1) + if err != nil { + return diag.FromErr(err) + } + for _, v := range portSecurityOptsList { + if v.PortSecurityDisabled { + if _, err := ports.DisablePortSecurity(portsClientV1, v.PortID).Extract(); err != nil { + return diag.FromErr(err) + } + } + } + } + log.Printf("[DEBUG] Instance id (%s)", InstanceID) if err != nil { return diag.FromErr(err) @@ -620,6 +683,7 @@ func resourceInstanceRead(_ context.Context, d *schema.ResourceData, m interface i["network_id"] = iFace.NetworkID i["subnet_id"] = subnetID i["port_id"] = portID + i["port_security_disabled"] = !iFace.PortSecurityEnabled if interfaceOpts.FloatingIP != nil { i["fip_source"] = interfaceOpts.FloatingIP.Source.String() i["existing_fip_id"] = interfaceOpts.FloatingIP.ExistingFloatingID @@ -798,6 +862,10 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter } if d.HasChange("interface") { + portsClientV1, err := CreateClient(provider, d, PortsPoint, VersionPointV1) + if err != nil { + return diag.FromErr(err) + } iOldRaw, iNewRaw := d.GetChange("interface") ifsOldSlice, ifsNewSlice := iOldRaw.([]interface{}), iNewRaw.([]interface{}) sort.Sort(instanceInterfaces(ifsOldSlice)) @@ -833,7 +901,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter if err := detachInterfaceFromInstance(client, instanceID, iOld); err != nil { return diag.FromErr(err) } - if err := attachInterfaceToInstance(client, instanceID, iNew); err != nil { + if err := attachInterfaceToInstance(client, portsClientV1, instanceID, iNew); err != nil { return diag.FromErr(err) } } @@ -869,7 +937,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter if err := detachInterfaceFromInstance(client, instanceID, iOld); err != nil { return diag.FromErr(err) } - if err := attachInterfaceToInstance(client, instanceID, iNew); err != nil { + if err := attachInterfaceToInstance(client, portsClientV1, instanceID, iNew); err != nil { return diag.FromErr(err) } } @@ -877,7 +945,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter for _, item := range ifsNewSlice[len(ifsOldSlice):] { iNew := item.(map[string]interface{}) - if err := attachInterfaceToInstance(client, instanceID, iNew); err != nil { + if err := attachInterfaceToInstance(client, portsClientV1, instanceID, iNew); err != nil { return diag.FromErr(err) } } @@ -912,7 +980,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter if err := detachInterfaceFromInstance(client, instanceID, iOld); err != nil { return diag.FromErr(err) } - if err := attachInterfaceToInstance(client, instanceID, iNew); err != nil { + if err := attachInterfaceToInstance(client, portsClientV1, instanceID, iNew); err != nil { return diag.FromErr(err) } } diff --git a/edgecenter/utils_instance.go b/edgecenter/utils_instance.go index 9d9a6ca3..8b9fb53b 100644 --- a/edgecenter/utils_instance.go +++ b/edgecenter/utils_instance.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "errors" "fmt" + "github.com/Edge-Center/edgecentercloud-go/edgecenter/port/v1/ports" "io" "log" "reflect" @@ -26,6 +27,13 @@ var instanceDecoderConfig = &mapstructure.DecoderConfig{ type instanceInterfaces []interface{} +type InstancePortSecurityOpts struct { + PortID string + PortSecurityDisabled bool + SubnetID string + IPAddress string +} + func (s instanceInterfaces) Len() int { return len(s) } @@ -112,6 +120,32 @@ func extractInstanceInterfaceToListCreate(interfaces []interface{}) ([]instances return interfaceInstanceCreateOptsList, nil } +// extractPortSecurityOpts creates a list of InstancePortSecurityOpts objects from a list of interfaces. +func extractPortSecurityOpts(interfaces []interface{}) ([]InstancePortSecurityOpts, error) { + portSecurityOptsList := make([]InstancePortSecurityOpts, 0) + for _, iFace := range interfaces { + iFaceMap := iFace.(map[string]interface{}) + + interfaceOpts, err := decodeInstanceInterfaceOpts(iFaceMap) + if err != nil { + return nil, err + } + + portSecDisabled := iFaceMap["port_security_disabled"].(bool) + + portSecurityOpts := InstancePortSecurityOpts{ + PortID: interfaceOpts.PortID, + PortSecurityDisabled: portSecDisabled, + SubnetID: interfaceOpts.SubnetID, + IPAddress: interfaceOpts.IPAddress, + } + + portSecurityOptsList = append(portSecurityOptsList, portSecurityOpts) + } + + return portSecurityOptsList, nil +} + // extractInstanceInterfaceToListRead creates a list of InterfaceOpts objects from a list of interfaces. func extractInstanceInterfaceToListRead(interfaces []interface{}) ([]instances.InterfaceOpts, error) { interfaceOptsList := make([]instances.InterfaceOpts, 0) @@ -341,19 +375,20 @@ func detachInterfaceFromInstance(client *edgecloud.ServiceClient, instanceID str } // attachInterfaceToInstance attach interface to instance. -func attachInterfaceToInstance(instanceClient *edgecloud.ServiceClient, instanceID string, iface map[string]interface{}) error { +func attachInterfaceToInstance(instanceClient, portsClient *edgecloud.ServiceClient, instanceID string, iface map[string]interface{}) error { iType := types.InterfaceType(iface["type"].(string)) opts := instances.InterfaceInstanceCreateOpts{ InterfaceOpts: instances.InterfaceOpts{Type: iType}, } + portID := iface["port_id"].(string) - switch iType { //nolint: exhaustive + switch iType { // nolint: exhaustive case types.SubnetInterfaceType: opts.SubnetID = iface["subnet_id"].(string) case types.AnySubnetInterfaceType: opts.NetworkID = iface["network_id"].(string) case types.ReservedFixedIPType: - opts.PortID = iface["port_id"].(string) + opts.PortID = portID } opts.SecurityGroups = getSecurityGroupsIDs(iface["security_groups"].([]interface{})) @@ -382,6 +417,42 @@ func attachInterfaceToInstance(instanceClient *edgecloud.ServiceClient, instance return err } + interfacesListAPI, err := instances.ListInterfacesAll(instanceClient, instanceID) + if err != nil { + return err + } + + portSecurityDisabled := iface["port_security_disabled"].(bool) + +LOOP: + for _, iFace := range interfacesListAPI { + if len(iFace.IPAssignments) == 0 { + continue + } + + portID = iFace.PortID + for _, assignment := range iFace.IPAssignments { + + subnetID := assignment.SubnetID + ipAddress := assignment.IPAddress.String() + + if opts.SubnetID == subnetID || opts.IPAddress == ipAddress || opts.PortID == portID { + if !iFace.PortSecurityEnabled != portSecurityDisabled { + switch portSecurityDisabled { + case true: + if _, err := ports.DisablePortSecurity(portsClient, portID).Extract(); err != nil { + return err + } + case false: + if _, err := ports.EnablePortSecurity(portsClient, portID).Extract(); err != nil { + return err + } + } + } + break LOOP + } + } + } return nil } @@ -511,7 +582,7 @@ func getSecurityGroupsIDs(sgsRaw []interface{}) []edgecloud.ItemID { } // getSecurityGroupsDifference finds the difference between two slices of edgecloud.ItemID. -func getSecurityGroupsDifference(sl1, sl2 []edgecloud.ItemID) (diff []edgecloud.ItemID) { //nolint: nonamedreturns +func getSecurityGroupsDifference(sl1, sl2 []edgecloud.ItemID) (diff []edgecloud.ItemID) { // nolint: nonamedreturns set := make(map[string]bool) for _, item := range sl1 { set[item.ID] = true diff --git a/examples/resources/edgecenter_instance/resource.tf b/examples/resources/edgecenter_instance/resource.tf index 651632a3..c6d3072b 100644 --- a/examples/resources/edgecenter_instance/resource.tf +++ b/examples/resources/edgecenter_instance/resource.tf @@ -60,10 +60,11 @@ resource "edgecenter_instance" "instance" { } interface { - type = "subnet" - network_id = edgecenter_network.network.id - subnet_id = edgecenter_subnet.subnet.id - security_groups = ["d75db0b2-58f1-4a11-88c6-a932bb897310"] + type = "subnet" + network_id = edgecenter_network.network.id + subnet_id = edgecenter_subnet.subnet.id + security_groups = ["d75db0b2-58f1-4a11-88c6-a932bb897310"] + port_security_disabled = true } metadata_map = {