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..7a30bf50 100644 --- a/edgecenter/resource_edgecenter_instance.go +++ b/edgecenter/resource_edgecenter_instance.go @@ -28,6 +28,7 @@ const ( InstanceDeleting int = 1200 InstanceCreatingTimeout int = 1200 InstancePoint = "instances" + PortsPoint = "ports" InstanceVMStateActive = "active" InstanceVMStateStopped = "stopped" @@ -223,6 +224,11 @@ func resourceInstance() *schema.Resource { Computed: true, Optional: true, }, + "port_security_disabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, }, }, }, @@ -394,12 +400,12 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter config := m.(*Config) provider := config.Provider - clientV1, err := CreateClient(provider, d, InstancePoint, VersionPointV1) + instancesClientV1, err := CreateClient(provider, d, InstancePoint, VersionPointV1) if err != nil { return diag.FromErr(err) } - clientV2, err := CreateClient(provider, d, InstancePoint, VersionPointV2) + instancesClientV2, err := CreateClient(provider, d, InstancePoint, VersionPointV2) if err != nil { return diag.FromErr(err) } @@ -449,11 +455,11 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter ifs := d.Get("interface").([]interface{}) if len(ifs) > 0 { - interfacesList, err := extractInstanceInterfaceToListCreate(ifs) + ifaceCreateOptsList, err := extractInstanceInterfaceToListCreate(ifs) if err != nil { return diag.FromErr(err) } - createOpts.Interfaces = interfacesList + createOpts.Interfaces = ifaceCreateOptsList } if metadata, ok := d.GetOk("metadata"); ok { @@ -479,15 +485,15 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter } log.Printf("[DEBUG] Instance create options: %+v", createOpts) - results, err := instances.Create(clientV2, createOpts).Extract() + results, err := instances.Create(instancesClientV2, createOpts).Extract() if err != nil { return diag.FromErr(err) } taskID := results.Tasks[0] log.Printf("[DEBUG] Task id (%s)", taskID) - InstanceID, err := tasks.WaitTaskAndReturnResult(clientV1, taskID, true, InstanceCreatingTimeout, func(task tasks.TaskID) (interface{}, error) { - taskInfo, err := tasks.Get(clientV1, string(task)).Extract() + InstanceID, err := tasks.WaitTaskAndReturnResult(instancesClientV1, taskID, true, InstanceCreatingTimeout, func(task tasks.TaskID) (interface{}, error) { + taskInfo, err := tasks.Get(instancesClientV1, string(task)).Extract() if err != nil { return nil, fmt.Errorf("cannot get task with ID: %s. Error: %w", task, err) } @@ -498,11 +504,32 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter return Instance, nil }, ) - log.Printf("[DEBUG] Instance id (%s)", InstanceID) if err != nil { return diag.FromErr(err) } + instanceID := InstanceID.(string) + + // Code below adjusts all interfaces PortSecurityDisabled opt + interfacesListAPI, err := instances.ListInterfacesAll(instancesClientV1, instanceID) + if err != nil { + return diag.FromErr(fmt.Errorf("error from getting instance interfaces: %w", err)) + } + + portsClientV1, err := CreateClient(provider, d, PortsPoint, VersionPointV1) + if err != nil { + return diag.FromErr(fmt.Errorf("error from creating ports client: %w", err)) + } + for _, iface := range ifs { + ifaceMap := iface.(map[string]interface{}) + err = adjustPortSecurityDisabledOpt(portsClientV1, interfacesListAPI, ifaceMap) + if err != nil { + return diag.FromErr(fmt.Errorf("error from port securtity disable option configuring. Interface: %#v, error: %w", ifaceMap, err)) + } + } + + log.Printf("[DEBUG] Instance id (%s)", InstanceID) + d.SetId(InstanceID.(string)) resourceInstanceRead(ctx, d, m) @@ -620,6 +647,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 +826,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 +865,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 +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) } } @@ -877,7 +909,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 +944,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..71328839 100644 --- a/edgecenter/utils_instance.go +++ b/edgecenter/utils_instance.go @@ -15,6 +15,7 @@ import ( edgecloud "github.com/Edge-Center/edgecentercloud-go" "github.com/Edge-Center/edgecentercloud-go/edgecenter/instance/v1/instances" "github.com/Edge-Center/edgecentercloud-go/edgecenter/instance/v1/types" + "github.com/Edge-Center/edgecentercloud-go/edgecenter/port/v1/ports" "github.com/Edge-Center/edgecentercloud-go/edgecenter/securitygroup/v1/securitygroups" "github.com/Edge-Center/edgecentercloud-go/edgecenter/servergroup/v1/servergroups" "github.com/Edge-Center/edgecentercloud-go/edgecenter/task/v1/tasks" @@ -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) } @@ -341,13 +349,13 @@ 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}, } - switch iType { //nolint: exhaustive + switch iType { // nolint: exhaustive case types.SubnetInterfaceType: opts.SubnetID = iface["subnet_id"].(string) case types.AnySubnetInterfaceType: @@ -382,6 +390,56 @@ func attachInterfaceToInstance(instanceClient *edgecloud.ServiceClient, instance return err } + interfacesListAPI, err := instances.ListInterfacesAll(instanceClient, instanceID) + if err != nil { + return fmt.Errorf("error from getting instance interfaces: %w", err) + } + + if err = adjustPortSecurityDisabledOpt(portsClient, interfacesListAPI, iface); err != nil { + return fmt.Errorf("cannot adjust port_security_disabled opt: %+v. Error: %w", iface, err) + } + + return nil +} + +// adjustPortSecurityDisabledOpt aligns the state of the interface (port_security_disabled) with what is specified in the +// iface["port_security_disabled"]. +func adjustPortSecurityDisabledOpt(portsClient *edgecloud.ServiceClient, interfacesListAPI []instances.Interface, iface map[string]interface{}) error { + portSecurityDisabled := iface["port_security_disabled"].(bool) + IPAddress := iface["ip_address"].(string) + subnetID := iface["subnet_id"].(string) + ifacePortID := iface["port_id"].(string) + +LOOP: + for _, iFace := range interfacesListAPI { + if len(iFace.IPAssignments) == 0 { + continue + } + + requestedIfacePortID := iFace.PortID + for _, assignment := range iFace.IPAssignments { + requestedIfaceSubnetID := assignment.SubnetID + requestedIfaceIPAddress := assignment.IPAddress.String() + + if subnetID == requestedIfaceSubnetID || IPAddress == requestedIfaceIPAddress || ifacePortID == requestedIfacePortID { + if !iFace.PortSecurityEnabled != portSecurityDisabled { + switch portSecurityDisabled { + case true: + if _, err := ports.DisablePortSecurity(portsClient, requestedIfacePortID).Extract(); err != nil { + return err + } + case false: + if _, err := ports.EnablePortSecurity(portsClient, requestedIfacePortID).Extract(); err != nil { + return err + } + } + } + + break LOOP + } + } + } + return nil } @@ -511,7 +569,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 = {