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

API driven, pluggable, provider creation and validation #18818

Closed
37 tasks done
skateman opened this issue May 29, 2019 · 39 comments
Closed
37 tasks done

API driven, pluggable, provider creation and validation #18818

skateman opened this issue May 29, 2019 · 39 comments

Comments

@skateman
Copy link
Member

skateman commented May 29, 2019

The API doesn't provide any kind of credential validation when adding provider, while the UI implements this feature. Therefore, it is possible to add a provider with invalid credentials through the API and we have no endpoint even to check if these credentials are correct.

There's a method included in each provider to create a MiqTask that checks the credentials, however, the input arguments for this task are different for each provider. On the UI side this difference is compensated via 🚒 🍝 🔥 if-else structures testing which provider is currently used.

case ems.to_s
when 'ManageIQ::Providers::Openstack::CloudManager'
  something
when 'ManageIQ::Providers::Amazon::CloudManager'
  something_else
when 'ManageIQ::Providers::Azure::CloudManager'
  something_totally_different
...

This goes totally in the opposite direction to our philosophy of having pluggable providers. Ideally we don't want anything in the UI that sends data to the backend based on the provider's type.

We're working with @Hyperkid123 on the API-driven provider forms and this is kinda blocking us.

ping @martinpovolny @Ladas @agrare

TODO:

@martinpovolny
Copy link
Member

martinpovolny commented May 29, 2019

Ping @dmetzger57 , @abellotti , @agrare .

Guys, this is an API feature request that is past what the UI team members so far did on the API. We need someone from the API team to implement this. Or at least provide some instructions on how this is to be done in the API so that it will get merged.

Can we get such help, please?

@dmetzger57
Copy link
Contributor

dmetzger57 commented May 29, 2019

As this is an API request, I look to @gtanzillo and @abellotti to assess when (I didn't say "if" 😄 ) we can help

@skateman
Copy link
Member Author

skateman commented May 29, 2019

I kinda started working on the API support but ran into the obstacles I've described above. I would be able to implement this thing in the API with some copy-paste engineering from the UI, but I don't think anyone would merge such 🍝

My idea was to utilize the AuthenticationMixin.validate_credentials_task method in an /api/providers/validate endpoint that would return us a task ID. We already have a mechanism to poll a task's status via the API, however, the generation of the input argument of the previously mentioned method is a mess...

@agrare
Copy link
Member

agrare commented May 29, 2019

There's a method included in each provider to create a MiqTask that checks the credentials, however, the input arguments for this task are different for each provider.

Yeah I never liked that this used raw_connect because the parameters are different for every provider. Would rather we design on a common ems.connect() interface that can be used generically.

@Fryguy
Copy link
Member

Fryguy commented May 29, 2019

Related to ManageIQ/manageiq-api#585 ?

@Fryguy
Copy link
Member

Fryguy commented May 29, 2019

I personally think this is extremely important for a solid API experience and greater pluggability on the UI side.

@Fryguy
Copy link
Member

Fryguy commented May 29, 2019

raw_connect was supposed to be the common interface, but then as new providers came on board, the pattern wasn't followed.

@agrare
Copy link
Member

agrare commented May 29, 2019

👍 Yeah agreed

@agrare
Copy link
Member

agrare commented May 29, 2019

Oh really? Usually all the raw_ methods are the provider specific version of the common interface
I don't think any of the raw_connect methods have the same parameters but I'll have to check

@Fryguy
Copy link
Member

Fryguy commented May 29, 2019

Amazon introduced the "service" name, and at the time, if I recall, we added an options parameter to deal with provider specifics...then it got refactored...and then I have no idea what happened 😆

@agrare
Copy link
Member

agrare commented May 29, 2019

Haha okay, well here is what we've got to work with:

./manageiq/app/models/manageiq/providers/embedded_ansible/provider.rb:  def self.raw_connect(base_url, username, password, verify_ssl)
./manageiq-providers-amazon/app/models/manageiq/providers/amazon/manager_mixin.rb:    def raw_connect(access_key_id, secret_access_key, service, region,
./manageiq-providers-redfish/app/models/manageiq/providers/redfish/manager_mixin.rb:    def raw_connect(username, password, host, port, protocol)
./manageiq-providers-kubevirt/app/models/manageiq/providers/kubevirt/infra_manager.rb:  def self.raw_connect(opts)
./manageiq-providers-google/app/models/manageiq/providers/google/manager_mixin.rb:    def raw_connect(google_project, google_json_key, options, proxy_uri = nil, validate = false)
./manageiq-providers-ovirt/app/models/manageiq/providers/redhat/infra_manager/api_integration.rb:    def raw_connect(opts = {})
./manageiq-providers-openshift/app/models/manageiq/providers/openshift/container_manager_mixin.rb:    def raw_connect(hostname, port, options)
./manageiq-providers-ansible_tower/app/models/manageiq/providers/ansible_tower/shared/provider.rb:    def raw_connect(base_url, username, password, verify_ssl)
./manageiq-providers-vmware/app/models/manageiq/providers/vmware/manager_auth_mixin.rb:    def raw_connect(server, port, username, password, api_version = '5.5', validate = false)
./manageiq-providers-vmware/app/models/manageiq/providers/vmware/infra_manager/vim_connect_mixin.rb:    def raw_connect(options)
./manageiq-providers-nuage/app/models/manageiq/providers/nuage/manager_mixin.rb:    def raw_connect(username, password, endpoint_opts)
./manageiq-providers-openstack/lib/manageiq/providers/openstack/legacy/openstack_handle/handle.rb:    def self.raw_connect_try_ssl(username, password, address, port, service = "Compute", options = nil,
./manageiq-providers-openstack/lib/manageiq/providers/openstack/legacy/openstack_handle/handle.rb:    def self.raw_connect(username, password, auth_url, service = "Compute", extra_opts = nil)
./manageiq-providers-openstack/app/models/manageiq/providers/openstack/manager_mixin.rb:    def raw_connect(password, params, service = "Compute")
./manageiq-providers-lenovo/app/models/manageiq/providers/lenovo/manager_mixin.rb:    def raw_connect(username, password, host, port, auth_type, verify_ssl, user_agent_label, validate = false, timeout: nil)
./manageiq-providers-kubernetes/app/models/manageiq/providers/kubernetes/virtualization_manager_mixin.rb:    def raw_connect(options)
./manageiq-providers-kubernetes/app/models/manageiq/providers/kubernetes/container_manager.rb:  def self.raw_connect(hostname, port, options)
./manageiq-providers-kubernetes/app/models/manageiq/providers/kubernetes/monitoring_manager_mixin.rb:    def raw_connect(options)
./manageiq-providers-scvmm/app/models/manageiq/providers/microsoft/infra_manager.rb:  def self.raw_connect(connect_params, validate = false)
./manageiq-providers-azure/app/models/manageiq/providers/azure/manager_mixin.rb:    self.class.raw_connect(client_id, client_key, azure_tenant_id, subscription, options[:proxy_uri] || http_proxy_uri, provider_region, default_endpoint)
./manageiq-providers-azure/app/models/manageiq/providers/azure/manager_mixin.rb:    def raw_connect(client_id, client_key, azure_tenant_id, subscription, proxy_uri = nil, provider_region = nil, endpoint = nil)
./manageiq-providers-foreman/app/models/manageiq/providers/foreman/provider.rb:  def self.raw_connect(base_url, username, password, verify_ssl)

So some of them take just an options hash but the vast majority take whatever they need for that provider

@Fryguy
Copy link
Member

Fryguy commented May 29, 2019

@agrare Ok, let's design a consistent interface at the model level somehow and then we can expose that via the /api/providers/validate that @skateman is proposing. We can take inspiration on how to design that form the if-else constructs at the UI level (since that's basically everything we'll need to do anyway)

@skateman
Copy link
Member Author

bump

@Fryguy Fryguy added the bug label Aug 3, 2019
@Fryguy
Copy link
Member

Fryguy commented Aug 3, 2019

@agrare Assigning to you just for tracking...we still need to design this.

@agrare
Copy link
Member

agrare commented Aug 6, 2019

@Fryguy and I discussed this and we are thinking something like this:

At the provider class level each provider would define their "parameters_for_create" in a JSON-schema format so taking Amazon as an example:

ManageIQ::Providers::Amazon::CloudManager.params_for_create

Then OPTIONS on /api/providers would return the params for the different provider types.

We would add a (names just an example, I'm terrible at naming) /api/providers#verify_credentials action which would take the filled in parameters and pass them to a new ExtManagementSystem.verify_credentials method common to all providers.

This will return a task which can be tracked for success/failure.

I'm thinking that the format for params_for_create will be either DDF like we have in sources-api for the different source_types (https://github.com/ManageIQ/sources-api/blob/master/db/seeds.rb#L23-L31) or something like an openapi spec.

@skateman
Copy link
Member Author

skateman commented Aug 7, 2019

@agrare this is perfect, cc @Hyperkid123

@Hyperkid123
Copy link

I'm thinking that the format for params_for_create will be either DDF like

Since we plan to use data driven forms for the component i would be great to use the DDF format for the authentication partials.

@agrare
Copy link
Member

agrare commented Aug 7, 2019

@Hyperkid123 sounds good to me! I was planning on using the parameters from sources-api for amazon as a starting point ref

@agrare
Copy link
Member

agrare commented Sep 4, 2019

Updated the description with a list of TODO items to complete this.

@skateman
Copy link
Member Author

I'll start working on the verify_credentials API endpoint.

@agrare
Copy link
Member

agrare commented Sep 30, 2019

@skateman we created a method on ExtManagementSystem that you can call from the API (#19346). It will return a task_id which can be given to the UI to wait for it to finish. It will update the task message with the error if it failed validation.

Fryguy added a commit to ManageIQ/manageiq-providers-ansible_tower that referenced this issue Sep 30, 2019
@skateman
Copy link
Member Author

@agrare @Fryguy there's an issue with network manager providers as they're implicitly tied to a parent_manager, so ManageIQ::Providers::Nuage::NetworkManager.supported_for_create? will return false. I know that all the other network managers are tied to a parent manager, but Nuage and also NSX-T aren't.

@chessbyte
Copy link
Member

Kudos and big thank you to @skateman @himdel @agrare @martinpovolny @Hyperkid123 @Fryguy and anybody else involved in getting this epic across the finish line!

@chessbyte chessbyte moved this from In progress to Kasparov in Roadmap Aug 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Kasparov
Roadmap
  
Kasparov
Development

No branches or pull requests

8 participants