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

module_utils/dimensiondata #17604

Merged
merged 10 commits into from
Jan 13, 2017
Merged

module_utils/dimensiondata #17604

merged 10 commits into from
Jan 13, 2017

Conversation

relaxdiego
Copy link
Contributor

@relaxdiego relaxdiego commented Sep 16, 2016

ISSUE TYPE

New Module Pull Request

COMPONENT NAME

dimensiondata

ANSIBLE VERSION
ansible 2.2.0 (for-upstream-pr bef03042b8) last updated 2016/09/15 12:53:04 (GMT -700)
  lib/ansible/modules/core: (detached HEAD db5cb54b23) last updated 2016/09/08 14:25:22 (GMT -700)
  lib/ansible/modules/extras: (for_devel 0b5e7136aa) last updated 2016/09/15 16:39:58 (GMT -700)
  config file = 
  configured module search path = Default w/o overrides
SUMMARY

This change contains common code required by the dimensiondata modules.

SPECIAL NOTE
  • Requires apache-libcloud
REQUIRED BY
  • TBD

Copy link
Member

@bcoca bcoca left a comment

Choose a reason for hiding this comment

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

Just from cursory review, a couple of issues, I only made one comment of each but both are repeated in several spots.

import sys
import ConfigParser
from os.path import expanduser
from libcloud.common.dimensiondata import API_ENDPOINTS
Copy link
Member

Choose a reason for hiding this comment

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

cannot assume non 'core' modules are in the system, this should attempt to import and then allow for the AnsibleModule class to report about the missing module in a 'friendly' way, see ec2.py for examples.

if is_uuid(locator):
net_id = locator
else:
networks = driver.ex_list_network_domains(location=location)
Copy link
Member

@bcoca bcoca Sep 20, 2016

Choose a reason for hiding this comment

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

don't all API calls need to capture exceptions?

Copy link

Choose a reason for hiding this comment

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

Exception handling is done in module code. This way we can keep the handling of the error specific to the module using the shared code.

Copy link
Member

Choose a reason for hiding this comment

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

it seems inconsistent as you do capture it in some cases

Copy link

Choose a reason for hiding this comment

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

Yes in some cases the error is always the same so we return False to ease module development. In other cases there are multiple error possibilities from API, some of which we ignore in one case and not another.

Copy link

Choose a reason for hiding this comment

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

If the above is an issue we can make all return the exception and consistently handle them in the module.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

+1 on raising a custom exception instead of failing silently.

if block_id is not 'False':
try:
block = driver.ex_get_public_ip_block(block_id)
except DimensionDataAPIException:
Copy link
Member

@bcoca bcoca Sep 20, 2016

Choose a reason for hiding this comment

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

Note: I'm assuming libcloud requires python >2.6, as such you can use Exception as e, the exc_info is only required for modules that are 2.4 compatible, which most cloud modules cannot be due to library dependencies.

Copy link

Choose a reason for hiding this comment

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

Typically we always use "except DimensionDataAPIException as e". This will be updated to reflect out standard process.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bcoca @aimonb using Exception as e causes some builds in shippit to fail though.

Copy link
Member

Choose a reason for hiding this comment

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

a) was just note, not required to pass review
b) if libcloud already requries 2.6 we can make an exception in the check as we do for other cloud modules.

Copy link

Choose a reason for hiding this comment

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

I vote for consistency of "except DimensionDataAPIException as e"

@relaxdiego
Copy link
Contributor Author

Rebased to ansible/devel

relaxdiego added a commit to relaxdiego/ansible that referenced this pull request Sep 21, 2016
@gundalow
Copy link
Contributor

@relaxdiego @mikeoutland This PR was added to ansible/community#124 we have discussed this and as we are now in feature freeze for 2.2 this (and related PRs) will not be reviewed/merged till after Ansible 2.2 has reached rc1 (release candidate 1). At that point we will have branched and allow new PRs to be merged.

#
# Common methods to be used by versious module components
import os
import ConfigParser
Copy link
Contributor

Choose a reason for hiding this comment

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

This formulation of importing configparser is not compatible with python3. You can use

from ansible.module_utis.six.moves import configparser

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, just checking - do you mean:

from ansible.module_utis.six.moves import configparser

or

from ansible.module_utis.six.moves import ConfigParser

(I've never seen this code before so it's a lot to take in, but it looks like the latter rather than the former?)

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, apologies for asking potentially stupid questions, but I'm jumping into this blind - it's been a while since I've written anything fancier than a simple script in Python and I'm a little rusty:

I can find ansible/module_utils/six.py but I'm not sure where moves comes from?

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, if I'm importing it as configparser I assume references to the ConfigParser class are still valid (again, sorry if this is a stupid question)?

region_list = filter(lambda i: i.startswith('dd-'), all_regions)

# Strip prefix
regions = [region[3:] for region in region_list]
Copy link
Contributor

Choose a reason for hiding this comment

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

List comprehensions and generator expressions are more pythonic than using filter. This one can be rewritten as a single listcomprehension or a combination of as two steps:

# One combined list comprehension
regions = [r[3:] for r in all_regions if r.startswith('dd-')]

# two steps, using a generator expression
region_list = (r for r in all_regions if r.startswith('dd-'))
regions = [r[3:] for r in region_list]

Get a network domain object by its name
"""
networks = driver.ex_list_network_domains(location=location)
found_networks = filter(lambda x: x.name == name, networks)
Copy link
Contributor

Choose a reason for hiding this comment

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

This usage of filter won't work on python3. filter on python3 will return a generator which will evaluate to true in the conditional below. Use a list comprehension so that found_networks ends up with an empty list on python3 which will evaluate to false.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same change needs to be made to many other uses of filter.

Get public IP block details
"""
# Block ID given, try to use it.
if block_id is not 'False':
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this works? block_id defaults to the boolean False in the parameters to this function. So you probably need to check:

if block_id is not False:

rather than checking against a string.

else:
blocks = list_public_ip_blocks(module, driver, network_domain)
if blocks is not False:
block = filter(lambda x: x.base_ip == base_ip, blocks)[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

This will fail on python3 for a similar reason as the conditional check noted above. filter returns a generator. The generator can't be indexed.

Use a list comprehension instead:

block = [b for b in blocks if b.base_ip == base_ip]

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks - I've replaced all uses of filter with comprehensions.

block = filter(lambda x: x.base_ip == base_ip, blocks)[0]
else:
module.exit_json(changed=False, msg="IP block starting with "
"'%s' does not exist." % base_ip)
Copy link
Contributor

Choose a reason for hiding this comment

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

the message here looks like a failure case rather than an exit case... Perhaps it should use module.fail_json or the message should be changed?

Stylistically, exit_json() cases should retun back to the main function in the module and let the exit_json() occur there. It's more flexible to changing needs inside of the module than calling exit_json() here.

@ansibot ansibot added needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. and removed needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. labels Jan 2, 2017
@jimi-c jimi-c removed the plugin label Jan 4, 2017
@ansibot ansibot added module_util needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. and removed needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. labels Jan 5, 2017
@ansibot ansibot added module_util new_module This PR includes a new module. needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. labels Jan 5, 2017
get_credentials will now look in environment, dotfile, and module configuration for credentials (in that order).
This method will get user_id and key from module configuration, environment, or dotfile.
Environment takes priority.
Get user_id and key from module configuration, environment, or dotfile.
Order of priority is environment, dotfile, module.
Copy link
Contributor

Choose a reason for hiding this comment

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

Near as I can tell the order of priority here is module, environment, dotfile. Module should be first, so the coded order is fine but the documentation here should agree with the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I think the current logic will only fall back to module if environment variable has not been specified: https://github.com/ansible/ansible/pull/17604/files/6c412fbeefa07e4296b33ec7544c5b1a69a6dcd8..85164a272274514877a6369877e851461a5acf0b#diff-0b1c579a3ccbeed5e582e7693e046cb6R112

I'll change the order, though, to put module first. Give me 5 mins.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

@abadger
Copy link
Contributor

abadger commented Jan 13, 2017

@tintoy. Looks good. Just a disagreement between the documentation and the code to straighten out. Once that's fixed, this is ready to merge.

@tintoy
Copy link
Contributor

tintoy commented Jan 13, 2017

Thanks again for your patience, BTW.

@abadger abadger merged commit b598575 into ansible:devel Jan 13, 2017
@abadger
Copy link
Contributor

abadger commented Jan 13, 2017

Merged to devel! thanks for your patience as well :-)

@tintoy
Copy link
Contributor

tintoy commented Jan 13, 2017

Great! I'll start looking at the first PR that depends on this :)

@tintoy tintoy mentioned this pull request Jan 16, 2017
@ansibot ansibot added feature This issue/PR relates to a feature request. and removed feature_pull_request labels Mar 4, 2018
@ansible ansible locked and limited conversation to collaborators Apr 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.3 This issue/PR affects Ansible v2.3 c:module_utils/ cloud feature This issue/PR relates to a feature request. module_util module This issue/PR relates to a module. needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. new_module This PR includes a new module. new_plugin This PR includes a new plugin.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet