-
Notifications
You must be signed in to change notification settings - Fork 897
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 Authentication create #14217
API Authentication create #14217
Conversation
@@ -4,6 +4,15 @@ module Authentications | |||
def authentications_query_resource(object) | |||
object.respond_to?(:authentications) ? object.authentications : [] | |||
end | |||
|
|||
def authentications_create_resource(parent, _type, _id, data) | |||
raise 'must supply a type' unless data['type'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is type needed when creating as a subcollection ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or is it the manager reference that's no longer needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abellotti it's the manager reference that's no longer needed
@@ -1,4 +1,20 @@ | |||
module Api | |||
class AuthenticationsController < BaseController | |||
def create_resource(_type, _id, data) | |||
validate_auth_attrs(data) | |||
klass = data['type'].constantize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we shouldn't be constantizing based on user specified data. Let's have the model lookup data['type'] for us and return the appropriate klass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abellotti I thought we decided the other day we would take in the type?
klass = data['type'].constantize | ||
# TODO: Temporary validation - remove | ||
raise 'type not currently supported' unless klass.respond_to?(:create_in_provider_queue) | ||
klass.create_in_provider_queue(parse_id(data['manager'], :providers), data.except('type', 'manager')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is authentications always targeted to manager type CI's or could they belong to other types ? if so, I wonder if we should have a more generic reference (maybe "resource" : { "href" : ... })
it 'requires that the type support create_in_provider_queue' do | ||
api_basic_authorize collection_action_identifier(:authentications, :create, :post) | ||
|
||
run_post(authentications_url, :action => 'create', :type => 'Authentication', :manager => 'blah') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, type is 'Authentication', should we default to this type if not specified ? (it is /api/authentications after all)
raise 'type not currently supported' unless klass.respond_to?(:create_in_provider_queue) | ||
manager_resource_id = parse_href(data['manager_resource']['href']).last | ||
task_id = klass.create_in_provider_queue(manager_resource_id, data.except('type', 'manager_resource')) | ||
MiqTask.find(task_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@miq-bot remove_label wip |
# TODO: Temporary validation - remove | ||
raise 'type not currently supported' unless klass.respond_to?(:create_in_provider_queue) | ||
task_id = klass.create_in_provider_queue(attrs['manager_resource'], attrs.except('type', 'manager_resource')) | ||
MiqTask.find(task_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the equivalent return as subcollection create should return the action_result signature which supports tasks, i.e action_result(true, desc, :task_id => task_id). create return signatures is either object created or action result, Thanks.
parse_href(data['manager_resource']['href']).last | ||
elsif data['manager_resource'].key?('id') | ||
data['manager_resource']['id'] | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couple of questions here.
what is the expected value of manager_resource for create_in_provider_queue ? Is it an id ? if so an id to which class ?
parse_href returns collection, id. If user sends in an href to a different resource, say /api/users/10, that means we're sending in a bogus 10. In which case could create_in_provider_queue supports an object for the first parameter ?
what is the else case, user specified "manager_resource" : 10 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abellotti good question.
It's an ID, and for what we're starting with here, it is an ExtManagementSystem
.
I originally limited it to providers
.
I believe @jameswnl mentioned that technically, a manager can be a different type of resource. Is that correct? And @jameswnl - do you think we can update create_in_provider_queue
to accept an object rather than the ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A credential is an Authentication
and is related to a manager
through the polymorphic resource_type/resource_id
. So in some other user cases, an Authentication
is related to other things, e.g. a Vm
.
In our use case here in create_in_provider[_queue]
, it has to be a manager
aka ExtManagementSystem
.
Yes, we can have create_in_provider[_queue]
to take in a manager
. But I don't know if there's any other use case prefer the id
. @Fryguy or @bdunne ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abellotti how do you think we handle this? Should we limit it to certain collections?
I am thinking perhaps we store a constant on the model that stores the manager type? And can parse it based off of that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping @abellotti
This pull request is not mergeable. Please rebase and repush. |
This pull request is not mergeable. Please rebase and repush. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise 'must supply a manager resource' unless data['manager_resource'] | ||
attrs = data.dup | ||
collection, id = parse_href(data['manager_resource']['href']) | ||
raise "#{collection} is not a valid manager resource" unless ::Authentication::MANAGER_TYPES.include?(collection) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
collection is API centric, model shouldn't need to know about this. If anything we could have the model check the equivalent class, i.e. check against collection_class(collection). Maybe model should provide a method to check the class for us (dealing with descendants and such).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per @Fryguy the class validation logic is probably better in create_in_provider_queue logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, I'll have a PR for that.
action_result(true, 'Creating Authentication', :task_id => task_id) | ||
rescue => err | ||
action_result(false, err.to_s) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicate code with primary collection authentication create code. Maybe add authentications service common methods in the api in lib/services/api/
add class method on authentication to return the type
use action_result remove constantize use action_result
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking better, thanks @jntullo a couple of minor changes.
@@ -9,6 +9,14 @@ def edit_resource(type, id, data) | |||
action_result(false, err.to_s) | |||
end | |||
|
|||
def create_resource(_type, _id, data) | |||
manager_resource, attrs = validate_auth_attrs(data) | |||
task_id = AuthenticationService.create_authentication(manager_resource, attrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would still prefer if we send in the object instead of the id, so this would work with future CI's.
elsif data['manager_resource'].key?('id') | ||
data['manager_resource']['id'] | ||
end | ||
[manager_resource, attrs] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lines 48-52 could be replaced with:
manager_collection, manager_id = parse_href(data['manager_resource']['href']
raise 'invalid manger_resource href specified' unless manager_collection && manager_id
manager_resource = resource_search(manager_id, manager_collection, collection_class(manager_collection)
Not sure we want to support manager_resource id references since it would be vague for handling multiple types.
Another concern just came up. @mzazrivec saw the issue:
Should it be the API's responsibility of adding in the user if not specified, based off of the request's user? cc: @jameswnl |
@mzazrivec we want to always have default organization. @Fryguy input? |
@jameswnl right, but we don't really want to work with this Ansible organization info on ManageIQ API level, do we? |
No, the API caller should not care about that. We should default the organization in the call on the backend for the embedded Provider. |
Another problem I noticed with current master:
|
@mzazrivec I believe that's an issue with the |
@mzazrivec actually I thought of something, can you try it now? |
@mzazrivec can you locate the logs in evm.log where this task is being executed? |
The problem above can also be reproduced from rails console:
|
The part from
|
The above error will go away when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 LGTM, @Fryguy are you good with merging this?
@@ -0,0 +1,10 @@ | |||
module Api | |||
class AuthenticationService | |||
def self.create_authentication(manager_resource, attrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor, but I feel like this should be named create_authenticaton_queue
or create_authenticaton_task
or something. Then the caller knows they are getting back a task, and it's clear that it's not a synchronous call.
type = descendants.find { |klass| klass.name == data['type'] } | ||
raise _('Must be an Authentication type') unless type | ||
type | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I don't like this on the model here. It feels like it's a generic thing that's being put into a single model
- This feels like a duplication of a lot of the work that the NewWithTypeStiMixin does. That is, finding the right subclass to instantiate via type. Given that, I feel like the "type" logic belongs to create_in_provider_queue itself, somehow at the base class, in a similar manner to how NewWithTypeStiMixin works.
create_authentication to create_authentication_task
Checked commits jntullo/manageiq@d1115a0~...eb89cb8 with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0 |
Merging on 🔴 anyway since these failures are a test failure with master and are unrelated to the code in question. |
cc: @h-kataria
@miq-bot add_label api, wip, enhancement
@miq-bot assign @abellotti