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

OPTIONS for /api/providers #3

Closed
wants to merge 1 commit into from

Conversation

enoodle
Copy link

@enoodle enoodle commented Aug 8, 2017

This is a migration of ManageIQ/manageiq#15660

@enoodle
Copy link
Author

enoodle commented Aug 8, 2017

@jntullo @abellotti PTAL

.select { |param| param.starts_with?("ems_type") } # 'parameters with "ems_type" name
.first.split('=').last # choosing only the first occuracne.
ems_class = ExtManagementSystem.descendants.select { |ems| ems.ems_type == req_class_name }.first
render :json => ems_class.respond_to?(:provider_settings) ? ems_class.provider_settings : {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you will want to use render_options(:providers, <your provider settings hash) here. This will return all of the default options that are passed back from OPTIONS /providers, and append your provider settings hash to it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jntullo I changed to render_options

@enoodle enoodle force-pushed the provider_options_api branch from 24a210d to 9fb1dfc Compare August 8, 2017 14:44
.split('?').last.split('&') # '?' for query, '&' connects parameters
.select { |param| param.starts_with?("ems_type") } # 'parameters with "ems_type" name
.first.split('=').last # choosing only the first occuracne.
ems_class = ExtManagementSystem.descendants.select { |ems| ems.ems_type == req_class_name }.first
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missed this earlier, but you should be able to get the ems type from just params[:ems_type]. Then you can actually use ExtManagementSystem.descendant_get(params[:ems_type]) here. That will return the descendant. An example of its usage can be found https://github.com/ManageIQ/manageiq-api/blob/master/lib/services/api/authentication_service.rb#L4

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jntullo I didn't know of descendant_get before, but I am not sure it will help here because it will require sending the full class name (ie ManageIQ::Providers::Openshift::ContainerManager) instead of the ems_type reported by the providers. I will change to use params[:ems_type]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@enoodle ah, gotcha! yeah, then descendant_get won't work.

this is just nit but you could do ExtManagementSystem.descendants.find { |ems| ems.ems_type == params[:ems_type] }

context "#options" do
it "returns options for queried provider class" do
api_basic_authorize
ExtManagementSystem.descendants.select { |ems| ems.respond_to?(:provider_settings) }.each do |ems_type|
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last thing 😄 you can simplify the spec by using expect_options_results, example here: https://github.com/ManageIQ/manageiq-api/blob/master/spec/requests/api/authentications_spec.rb#L480

@enoodle enoodle force-pushed the provider_options_api branch from c256d49 to cfc7b9a Compare August 8, 2017 16:02

context "#options" do
it "returns options for queried provider class" do
api_basic_authorize
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing an OPTIONS request shouldn't require authorization

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imtayadeway I am not sure how to remove this requirement. I also see this in many other examples: cluster, hosts, authentications. How do you suggest solving this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize this was still an issue.....I created #8 to resolve this

@@ -85,6 +85,11 @@ def import_vm_resource(type, id = nil, data = {})
end
end

def options
ems_class = ExtManagementSystem.descendants.find { |ems| ems.ems_type == params[:ems_type] }
render_options(:providers, ems_class.respond_to?(:provider_settings) ? ems_class.provider_settings : {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you don't render anything when you don't provide the ems_type param. Did you you consider rendering all the EMSs and their provider settings and leaving it to the client to figure out?

context "#options" do
it "returns options for queried provider class" do
api_basic_authorize
ExtManagementSystem.descendants.select { |ems| ems.respond_to?(:provider_settings) }.each do |ems_type|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your test logic here mirrors that of the implementation, so I'm wondering what value this test is providing? IMO, using literals to represent expected values is much clearer and will provide useful feedback in the case of breakages or false assumptions about the implementations.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imtayadeway doing so will force me to use specific providers names as this is only implemented for "ManageIQ::Providers::Kubernetes::ContainerManager" currently. I am afraid of breaking tests when things changes in another repo (ie someone will change the way options are saved there and tests here will be red). I also agree that the test logic is not super helpful but it helped me.
I will try to add a test with this provider and options that I don't think will change anytime soon.

@enoodle enoodle force-pushed the provider_options_api branch 2 times, most recently from fe1ba1f to af45586 Compare August 9, 2017 08:58
@enoodle enoodle closed this Aug 9, 2017
@enoodle enoodle reopened this Aug 9, 2017
@enoodle enoodle force-pushed the provider_options_api branch from af45586 to 1e2b12f Compare August 9, 2017 09:02
@@ -85,6 +85,21 @@ def import_vm_resource(type, id = nil, data = {})
end
end

def options
if params[:ems_type].blank?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have concerns over this param and its discoverability. At present AFAICT it is not discoverable, meaning it will have to be documented somewhere, and I'm not totally comfortable with adding complexity to OPTIONS calls. Is it needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a must, but I though it will be nice. I don't mind documenting it (where?) but I can also remove this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also #3 (comment) for my explanation there - I think I'd prefer not including this unless there is a distinct need for it. If that is the case, I suspect OPTIONS might not be the right solution

if params[:ems_type].blank?
all_options = Hash[
ExtManagementSystem.descendants.collect do |ems|
[ems.ems_type, ems.respond_to?(:provider_settings) ? ems.provider_settings : {}]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do provider settings come from the Settings object? Could this information be got at through the settings API?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they come from "per-provider" options, for example: ManageIQ/manageiq-providers-kubernetes#45

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that's not in here ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those options themselves are per provider instance.
What I am serving here are only their descriptions but belong there as they are static and not configurable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow? I'd expect per-instance settings to be revealed via GETs to the collection member URI. We augment OPTIONS responses only as a limited way to reveal metadata - i.e. data about the resource itself in the abstract.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. But here we are not serving the values of those options but the answer to the question "what per-provider options are for this provider type?". This is the static description of those options. please look at https://github.com/ManageIQ/manageiq-providers-kubernetes/pull/45/files#diff-47711b761083b6ce40dacb7d3ee68f8b for example


context "OPTIONS /api/providers" do
it "returns options for all providers when no query" do
api_basic_authorize
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that #8 has been merged you can remove this and subsequent calls to api_basic_authorize

@enoodle enoodle force-pushed the provider_options_api branch 2 times, most recently from 317ad45 to 7f6d4c0 Compare August 9, 2017 18:09
@@ -85,6 +85,16 @@ def import_vm_resource(type, id = nil, data = {})
end
end

def options
all_options = Hash[
ExtManagementSystem.descendants.collect do |ems|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer inject or each_with_object here

[ems.ems_type, ems.respond_to?(:provider_settings) ? ems.provider_settings : {}]
end
]
all_options.delete(nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which EMSs have an ems_type of nil?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtManagementSystem.descendants.select { |ems| ems.ems_type == nil }.map { |ems| ems.name }
=> ["ManageIQ::Providers::BaseManager",
 "ManageIQ::Providers::DatawarehouseManager",
 "ManageIQ::Providers::MiddlewareManager",
 "ManageIQ::Providers::NetworkManager",
 "ManageIQ::Providers::ProvisioningManager",
 "ManageIQ::Providers::AutomationManager",
 "ManageIQ::Providers::CloudManager",
 "ManageIQ::Providers::ContainerManager",
 "ManageIQ::Providers::ConfigurationManager",
 "ManageIQ::Providers::StorageManager",
 "ManageIQ::Providers::InfraManager",
 "ManageIQ::Providers::EmbeddedAutomationManager",
 "ManageIQ::Providers::ExternalAutomationManager"]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will .leaf_subclasses give you what you need?

@enoodle enoodle force-pushed the provider_options_api branch from 7f6d4c0 to accf865 Compare August 9, 2017 20:31
@imtayadeway
Copy link
Contributor

@enoodle just one more suggestion in #3 (comment). Thanks!

@enoodle
Copy link
Author

enoodle commented Aug 10, 2017

@imtayadeway PTAL

@@ -85,6 +85,13 @@ def import_vm_resource(type, id = nil, data = {})
end
end

def options
all_options = ExtManagementSystem.leaf_subclasses.inject({}) do |ao, ems|
ao.merge(ems.ems_type => ems.respond_to?(:provider_settings) ? ems.provider_settings : {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unfortunate that not all EMSs respond to this message. Though I think this if fine for now - do you think you could follow this up by trying to push this default down into the base class?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I changed this to address leaf_subclasses of ManageIQ::Providers::BaseManager instead of ExtManagementSystem and it will be easy to add

def self.provider_settings()
  {}
end

to this class.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it "returns options for all providers when no query" do
run_options(providers_url)
expect(response.parsed_body["data"].keys.count).to eq(
ExtManagementSystem.leaf_subclasses.select { |ems| !ems.ems_type.blank? }.count
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any leaf subclasses for which this is not true?

Copy link
Author

@enoodle enoodle Aug 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No (that I know of), but if a new one will be created I think it will break this test. I will remove the select.

@enoodle
Copy link
Author

enoodle commented Aug 14, 2017

@imtayadeway PTAL

Copy link
Contributor

@imtayadeway imtayadeway left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks @enoodle for your patience with my many questions.

Off to @abellotti

@enoodle enoodle changed the title OPTIONS for /api/providers [WIP] OPTIONS for /api/providers Aug 15, 2017
@enoodle
Copy link
Author

enoodle commented Aug 15, 2017

@miq-bot add_label wip
We will change the provider_settings function name to options_description

@miq-bot miq-bot added the wip label Aug 15, 2017
@enoodle enoodle changed the title [WIP] OPTIONS for /api/providers OPTIONS for /api/providers Aug 24, 2017
@enoodle enoodle closed this Aug 24, 2017
@enoodle enoodle reopened this Aug 24, 2017
@miq-bot miq-bot removed the wip label Aug 24, 2017
@enoodle
Copy link
Author

enoodle commented Aug 24, 2017

@imtayadeway @abellotti with ManageIQ/manageiq#15799 being approved, can we merge this one?

@@ -86,6 +86,13 @@ def import_vm_resource(type, id = nil, data = {})
end
end

def options
all_options = ManageIQ::Providers::BaseManager.leaf_subclasses.inject({}) do |ao, ems|
ao.merge(ems.ems_type => ems.respond_to?(:options_description) ? ems.options_description : {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@enoodle if ManageIQ/manageiq#15799 is merged, can you remove this respond_to??

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed, tests here will only be green after ManageIQ/manageiq#15799 is merged

@enoodle enoodle force-pushed the provider_options_api branch from 1aa3e25 to 87c533f Compare August 24, 2017 14:41
@abellotti
Copy link
Member

@enoodle can you attach sample output you're getting with OPTIONS /api/providers ? just the data part of the output is sufficient. Thanks.

@enoodle
Copy link
Author

enoodle commented Aug 24, 2017

Output example from current masters:

api_provider_to_delete.txt

@abellotti
Copy link
Member

abellotti commented Aug 24, 2017

I wonder if there might be some common options we'd want to provide in the future for all providers, in which case we may want to nest the output one level down,

i.e.

"data" => {
   "provider_settings" => {
       "ansible_tower_automation" => ...,
       "azure" => ...,
       ...
   }
}

@enoodle
Copy link
Author

enoodle commented Aug 25, 2017

@abellotti Then you suggest to have the common options description under "provider_settings"? It will make for a more compact output, but will be more awkward to consume so I don't like it too much.

@abellotti
Copy link
Member

@enoodle true, it is an extra level to fetch, but would keep the return signature future-proof.

@enoodle enoodle force-pushed the provider_options_api branch from 87c533f to 37f3b81 Compare September 3, 2017 13:07
@enoodle
Copy link
Author

enoodle commented Sep 3, 2017

@abellotti 👍 I added the "provider_settings" step.

@enoodle enoodle force-pushed the provider_options_api branch from 37f3b81 to cb3b52c Compare September 4, 2017 08:40
@miq-bot
Copy link
Member

miq-bot commented Sep 4, 2017

Checked commit enoodle@cb3b52c with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0
2 files checked, 1 offense detected

app/controllers/api/providers_controller.rb

@enoodle
Copy link
Author

enoodle commented Sep 4, 2017

Travis for this seems to be broken as it is testing the wrong commit. I will close this one to open a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants