Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: data source: openstack_networking_port_v2 #512

Closed
kayrus opened this issue Dec 7, 2018 · 11 comments
Closed

Feature request: data source: openstack_networking_port_v2 #512

kayrus opened this issue Dec 7, 2018 · 11 comments

Comments

@kayrus
Copy link
Collaborator

kayrus commented Dec 7, 2018

Affected Resource(s)

Please list the resources as a list, for example:

  • openstack_networking_port_v2

Expected Behavior

Import neutron ports, which were created automatically by the backend, e.g. owner:

  • network:f5lbaasv2
  • manila:share

Actual Behavior

There is no openstack_networking_port_v2 data resource available

Important Factoids

Ideally it should be possible to import multiple ports, filtered by ListOpts. Then there should be a way to modify them, like add these ports into the security group. I don't like terraform import way, because I'd expect to import resources dynamically in the TF manifest. Maybe someone have another thought on it.

References

Some thoughts could be found here: hashicorp/terraform#10123
https://www.terraform.io/docs/plugins/provider.html#importer

@jtopjian
Copy link
Contributor

jtopjian commented Dec 7, 2018

I believe the kind of functionality you've described has been discussed as future features in Terraform core, but they're not in a state beyond discussion right now. It would be great to have Terraform able to automatically generate Terraform code when importing resources, but right now, the resource will only be imported into the state and the user must write the Terraform code to do any further changes. It's a limitation in some use-cases for sure, but at least it's possible to do some kind of importing right now :)

Ideally it should be possible to import multiple ports

This has also been discussed and there are some data sources in other providers that return multiple results. I inquired about these kinds of resources a while ago and learned that they were more for experimenting and edge cases.

With that in mind, if there was a valid case to have a data source return a list of multiple port UUIDs, we can see how that would look. But the limitation here would be that only a list of UUIDs would be returned - no other attributes. Someone previously started work on https://github.com/terraform-providers/terraform-provider-openstack/pull/139 which would do this for images.

But ideally, data sources should return a single resource.

Again, I can see how these are limitations for some use-cases. Perhaps future versions of Terraform will allow more flexibility here.

Let me know if this helps clarify anything or if you have any questions.

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 6, 2019

What do you think about the idea below:

  • Create a new data source: openstack_networking_port_v2, which will return the list of port IDs, specified by a filter
  • Create a new type of port resource: openstack_networking_port_manage_v2
  • It will act as a resource combined with a data source (will retrieve data by IDs, returned by a openstack_networking_port_v2 data source)
  • It will import fields, which were not specified in the *.tf manifest
  • It will modify fields, which were specified in the *.tf manifest

@jtopjian
Copy link
Contributor

jtopjian commented Jan 6, 2019

Re-reading the original post, I think I misunderstood a number of things.

For some reason, I thought you were asking about Terraform's ability to generate HCL code when doing an import. My comment starting with "I believe the kind of functionality you've described has been discussed as future features in Terraform core," applies here.

Secondly, I thought you were also asking about a data source's ability to return more than one result. My comment starting with "This has also been discussed and there are some data sources in other providers that return multiple results" applies here.

Create a new data source: openstack_networking_port_v2, which will return the list of port IDs, specified by a filter

A data source named openstack_networking_port_v2 will only return a single port. If you wanted to experiment with a data source which returned multiple IDs, then the discussion about #139 is valid here and the data source would be named something like openstack_networking_port_ids_v2. My prior comment still holds true, though: "I inquired about these kinds of resources a while ago and learned that they were more for experimenting and edge cases.", so I can't guarantee that something like this would be merged.

Create a new type of port resource: openstack_networking_port_manage_v2
It will act as a resource combined with a data source (will retrieve data by IDs, returned by a openstack_networking_port_v2 data source)
It will import fields, which were not specified in the *.tf manifest
It will modify fields, which were specified in the *.tf manifest

This feels like a workaround for having to do terraform import, generate the HCL, make modifications, and then doing terraform apply. I agree that doing those 4 steps is a nuisance, but we need to take a hard look at why such a resource needs to exist: you want to make changes to something you didn't create.

I recall an earlier discussion about a similar situation: a user wanted to apply security groups to a load balancer's port: hashicorp/terraform#11066

The way this works is isn't optimal and my comment from the above link still stands:

I'd prefer not having to do this

When a load balancer is created, the vip_port_id is returned. The Create function then does a second phase of work: https://github.com/terraform-providers/terraform-provider-openstack/blob/master/openstack/resource_openstack_lb_loadbalancer_v2.go#L146-L150

If Neutron is creating ports that are failing to meet important requirements (ie: no security groups are applied, so they area open to the world), then I recommend modifying resources with a similar pattern (ie: add security_group_ids to the schema of the share resource) so that everything is handled within the resource in question.

But these situations are pointing out limitations of the OpenStack API: the Share and LBaaS API should provide the ability to apply security groups to the port/instance or provide the ability specify a port ID upon creation. Since they don't, Terraform is now making up for that lack of basic functionality, and that's not a good situation to be in.

One reason it's not good is because these limitations might be fixed in the future. Using the vip_port_id example, back in January 2017, it was not possible to specify a port ID when creating a load balancer. Now it is possible, but only for new OpenStack releases and around in circles we go 😵

Making decisions about when this is appropriate will need to be handled case-by-case. Having Terraform provide the ability to circumvent arbitrary limitations of the OpenStack API isn't a situation I want to be in (ie: openstack_networking_managed_port_v2). For example, if you are looking to make niche changes to these service-created ports (ie: you want to rename them to something of your preference), then I recommend falling back to doing a manual terraform import, generating the HCL code, and then making the changes, followed by a terraform apply.

To summarize:

Amending openstack_sharedfilesystem_share_v2 to be able to add security_group_ids to the service-created port is the best way to go for a situation like this. Providing an openstack_networking_managed_port_v2 resource to make any changes to any port is too arbitrary in its purpose and something I wouldn't be comfortable supporting.

Let me know if I am totally misunderstanding something here.

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 6, 2019

@jtopjian Thanks for your thoughts. I expected an answer like this. LB security groups function manages only the LB port, but not the LB instance ports (from which the monitoring checks are happen). The same applies for the openstack_sharedfilesystem_sharenetwork_v2 (not openstack_sharedfilesystem_share_v2). Nevertheless I prepared a PR, which could be a compromise.

It will allow to use port IDs by an independent terraform provider.

@jtopjian
Copy link
Contributor

jtopjian commented Jan 7, 2019

but not the LB instance ports (from which the monitoring checks are happen)

Do you mean the individual openstack_compute_instance_v2 instances which the load balancer directs traffic to? If so, then it's possible to use openstack_networking_port_v2 to create a port and then specify that port in openstack_compute_instance_v2.

I really want to make sure I'm understanding your use-case because I absolutely do not want to dismiss something valid. My current understanding is that you primarily want to modify service-created ports and secondarily want to do it in bulk?

Can you sketch out some HCL code (you can even use non-existent resources for illustration) on what you're trying to achieve?

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 7, 2019

An example for lbaas

My environment creates tree LBaaS ports for each hardware load balancer assigned to the network:

$ openstack port list --device-owner network:f5lbaasv2
+--------------------------------------+---------------------------------------------------+-------------------+-----------------------------------------------------------------------------+--------+
| ID                                   | Name                                              | MAC Address       | Fixed IP Addresses                                                          | Status |                           
+--------------------------------------+---------------------------------------------------+-------------------+-----------------------------------------------------------------------------+--------+
| 16b94c86-6998-4170-b691-a8e79dec334a | region-a-f5                                       | fa:16:3e:db:2d:92 | ip_address='10.180.0.9', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e'   | ACTIVE |
| 4940da39-0d77-4c06-8dc7-10dd406aa7f3 | region-b-f5                                       | fa:16:3e:fe:a1:4b | ip_address='10.180.0.10', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e'  | ACTIVE |
| a815774a-006f-4931-a4af-91145d506a9f | loadbalancer-60b89492-0e96-44c8-8009-655864e5b6bd | fa:16:3e:03:fd:d9 | ip_address='10.180.0.11', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e'  | ACTIVE |
+--------------------------------------+---------------------------------------------------+-------------------+-----------------------------------------------------------------------------+--------+

First two are used by a lbaas member monitor.
Third one is the actual LB VIP port, which connects to the upstream to serve the request. And it has a proper security group.

An example for manila

Once you create a sharednetwork + share, manila driver automatically creates two ports, corresponding to the share server (usually two: master, backup)

$ openstack port list --device-owner manila:share
+--------------------------------------+------+-------------------+-----------------------------------------------------------------------------+--------+
| ID                                   | Name | MAC Address       | Fixed IP Addresses                                                          | Status |
+--------------------------------------+------+-------------------+-----------------------------------------------------------------------------+--------+
| 7a7fa824-b67b-47d4-b426-5ba6bf535cb8 |      | fa:16:3e:4e:ff:cc | ip_address='10.180.0.146', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e' | ACTIVE |
| f2143111-3ee7-48f3-9f22-931dea0a4c70 |      | fa:16:3e:c0:21:46 | ip_address='10.180.0.145', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e' | ACTIVE |
+--------------------------------------+------+-------------------+-----------------------------------------------------------------------------+--------+

These IP addresses are reflected in the export_locations attributes. And share client connects to these IP addresses. However to secure the network, we need to know which IP addresses belong to the share server. We need to whitelist SMB, NFS, kerberos, AD, etc ports from these IPs.

HCL sketch

Here is the combination example of the both data sources referenced in this issue:

data "openstack_networking_port_ids_v2" "port" {
  device_owner = "network:f5lbaasv2"
}

data "openstack_networking_port_v2" "port" {
  count = "${length(data.openstack_networking_port_ids_v2.port.ids)}"
  port_id = "${element(data.openstack_networking_port_ids_v2.port.ids, count.index)}"
}

output "foo" {
  value = "${data.openstack_networking_port_ids_v2.port.ids}"
}

output "bar" {
  value = "${data.openstack_networking_port_v2.port.*.all_security_group_ids}"
}

Once we get the IDs, I'm planning to create a combined data source/resource networking_port_manage_v2 resource to ensure that these ports have corresponding security groups assigned:

networking_port_manage_v2 {
  count = "${length(data.openstack_networking_port_ids_v2.port.ids)}"
  port_id = "${element(data.openstack_networking_port_ids_v2.port.ids, count.index)}"
  # ensure that referenced ports have a security group
  security_group_ids = [
    "%UUID%",
  ]
}

This will allow me to get rid of the hacky local-exec shell provisioners with loops and neutron CLI calls.

@jtopjian
Copy link
Contributor

jtopjian commented Jan 8, 2019

Thanks!

Once we get the IDs, I'm planning to create a combined data source/resource networking_port_manage_v2 resource to ensure that these ports have corresponding security groups assigned:

We have an openstack_networking_floatingip_associate_v2 resource which is used to associate a floating IP to a port. This is used in situations where the user has already allocated themselves a floating IP and do not want to risk losing that IP.

openstack_networking_floatingip_associate_v2 sets precedence for creating other resources which help provide workarounds, but I'm really cautious about which ones are created -- the resource needs to serve a purpose to a large group of users.

I think creating a resource called openstack_networking_port_secgroup_associate_v2 might be an acceptable compromise here. This resource would apply a list of security groups to a port, with the understanding that the user must not do this same thing with the openstack_networking_port_v2 resource.

This would benefit your use-case as well as users who, for some reason or another, are prevented from creating ports in their clouds (which is an unfortunate real situation).

The only remaining piece here is the openstack_networking_port_ids_v2 data source. Merging this data source is going to set precedence for other data sources in this provider and I'm not sure I want to go there yet. Like I mentioned, it's entirely possible this problem is solved in core and would immediately cause openstack_*_*_ids data sources to become invalid.

Even if you had to declare 5 openstack_networking_port_v2 data sources, each of which uniquely identified a port, is this possible to do? Does each service port have enough unique attributes that you would be able to issue a unique query for it?

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 8, 2019

openstack_networking_port_secgroup_associate_v2 makes sense. However it will work only with manila ports, not lbaas. I am able to identify manila port IDs according to share data source (though it looks ugly):

data "openstack_sharedfilesystem_share_v2" "hostctrl" {
  name = "${var.sid}_hostctrl"
}

data "openstack_sharedfilesystem_share_v2" "tempdata" {
  name = "${var.sid}_tempdata"
}

data "openstack_sharedfilesystem_share_v2" "scripts" {
  name = "${var.sid}_scripts"
}

data "openstack_sharedfilesystem_share_v2" "repository" {
  name = "${var.sid}_repository"
}

#### manila ports security groups START
data "openstack_networking_secgroup_v2" "manila" {
  name = "manila"
}

locals {
  share_ips = "${sort(distinct(list(
                 element(split(":", data.openstack_sharedfilesystem_share_v2.hostctrl.export_locations.0.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.hostctrl.export_locations.1.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.tempdata.export_locations.0.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.tempdata.export_locations.1.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.scripts.export_locations.0.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.scripts.export_locations.1.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.repository.export_locations.0.path), 0),
                 element(split(":", data.openstack_sharedfilesystem_share_v2.repository.export_locations.1.path), 0),
               )))}"
}

data "openstack_networking_port_v2" "manila_ports" {
  count = "${length(local.share_ips)}"
  fixed_ip = "${element(local.share_ips, count.index)}"
}

resource "openstack_networking_port_secgroup_associate_v2" "ports" {
  count = "${length(local.share_ips)}"
  port_id = "${element(data.openstack_networking_port_v2.manila_ports.*.id, count.index)}"
  security_group_ids = [
    "${data.openstack_networking_secgroup_v2.manila.id}",
  ]
}
#### manila ports security groups END

But I'm not able to find any hooks for lbaas monitor ports.

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 8, 2019

@jtopjian, I noticed #435 issue by accident. Could be another case for the openstack_networking_port_manage_v2. Take a look on this commit, it doesn't look complicated.

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 11, 2019

Additionally it might me useful to add a name/description regex, especially when port names/descriptions contain some hints, like in this situation:

$ openstack port list --device-owner network:f5lbaasv2
+--------------------------------------+---------------------------------------------------+-------------------+-----------------------------------------------------------------------------+--------+
| ID                                   | Name                                              | MAC Address       | Fixed IP Addresses                                                          | Status |                           
+--------------------------------------+---------------------------------------------------+-------------------+-----------------------------------------------------------------------------+--------+
| 16b94c86-6998-4170-b691-a8e79dec334a | region-a-f5                                       | fa:16:3e:db:2d:92 | ip_address='10.180.0.9', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e'   | ACTIVE |
| 4940da39-0d77-4c06-8dc7-10dd406aa7f3 | region-b-f5                                       | fa:16:3e:fe:a1:4b | ip_address='10.180.0.10', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e'  | ACTIVE |
| a815774a-006f-4931-a4af-91145d506a9f | loadbalancer-60b89492-0e96-44c8-8009-655864e5b6bd | fa:16:3e:03:fd:d9 | ip_address='10.180.0.11', subnet_id='11deb7f4-b5ea-478e-bd92-8bba5e678b2e'  | ACTIVE |
+--------------------------------------+---------------------------------------------------+-------------------+-----------------------------------------------------------------------------+--------+

UPD: But I believe regex is not supported on the neutron side and this feature will try to list all available ports, then regexp them on the client side. It should be used with a combination of other fields...

@kayrus
Copy link
Collaborator Author

kayrus commented Jan 19, 2019

Found another use case for the port security groups #383

@kayrus kayrus closed this as completed Jan 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants