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

Add ManageIQ alert profiles module #32354

Merged
merged 1 commit into from
Jan 10, 2018
Merged

Add ManageIQ alert profiles module #32354

merged 1 commit into from
Jan 10, 2018

Conversation

elad661
Copy link
Contributor

@elad661 elad661 commented Oct 30, 2017

SUMMARY

ManageIQ is an open source management platform for Hybrid IT.

This change is adding:

manageiq_alert_profiles module, responsible for alert profiles management in ManageIQ.
(alert profiles are collections of alert policies).

All the modules, including docs, tests and usage examples can be found here

Currently, the only requirement for the module is manageiq-api-client-python,
the module also requires ManageIQ/manageiq-api#149 in the ManageIQ server.

ISSUE TYPE
  • New Module Pull Request
COMPONENT NAME

manageiq_alert_profiles.py (module)

ANSIBLE VERSION
ansible 2.5.0

@elad661
Copy link
Contributor Author

elad661 commented Oct 30, 2017

cc @yaacov @cben - please review.

@ansibot
Copy link
Contributor

ansibot commented Oct 30, 2017

@ansibot ansibot added affects_2.5 This issue/PR affects Ansible v2.5 community_review In order to be merged, this PR must follow the community review workflow. module This issue/PR relates to a module. needs_triage Needs a first human triage before being processed. new_contributor This PR is the first contribution by a new community member. new_module This PR includes a new module. new_plugin This PR includes a new plugin. support:community This issue/PR relates to code supported by the Ansible community. labels Oct 30, 2017
@ansibot
Copy link
Contributor

ansibot commented Oct 30, 2017

@abellotti @cben @dkorn @gtanzillo @yaacov @zgalor

As a maintainer of a module in the same namespace this new module has been submitted to, your vote counts for shipits. Please review this module and add shipit if you would like to see it merged.

click here for bot help

description:
- absent - alert profile should not exist,
- present - alert profile should exist,
- list - return a list of alert policies.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo? "list of alert profiles"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep, it was a typo. Fixed now. (I'll squash the commits before this PR will be merged)


# assign / unassign the alert policies, if needed

if to_remove:
Copy link
Contributor

Choose a reason for hiding this comment

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

you may accidentally remove policies user did not explicitly specify state: "absent" for policies that currently exist but no the list the user gave.

for example:
if I have policies A and B
and I ask in the playbook to make sure A is present.
the play book may inadvertently delete policy B.

p.s.
you may want to specify new actions to add and remove policies from a profile
e.g. "assign and set policies" ?

cc @cben @joelddiaz ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

from my experience with configuration management tools similar to ansible, when you define something using the playbook you want it to act like this - to make sure the configuration on the server is 100% in sync with the automated configuration.

"absent" and "present" are the states of the profile itself, when the state is "present" that means "it needs to 1) exist 2) be configured exactly how it's described in the playbook".

that's my take on it, but I'll be happy to change it if the ops people decide they want it to behave differently.

Copy link
Contributor

Choose a reason for hiding this comment

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

as someone using this module, i would be surprised if the behavior when creating a new alert profile A, a separate unrelated profile B disappeared.

a different way of saying this is if the product ships with profiles X and Y, then while creating a new profile A, i shouldn't have to provide (or know about) X and Y to the ansible module call when all i want to do is create/edit/delete my own alert profile A.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you misunderstood the question. This has nothing to do with "unrelated alert profiles", let me paraphrase:

Assume you have manually added an alert profile X, and assigned the alerts A, B and C to it.
If run an ansible playbook that defines alert profile X with only A and B assigned, it will remove C from the existing profile. Is that a kind of behaviour you expect?

If you have a profile Y that is not defined in the playbook, the module will (obviously) not touch it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I absolutely did misunderstand then.

For the primary use case, I think we do want an Ansible call to create/update profile X with alerts A and B to make sure that only alerts A & B are associated with profile X.

There is an edge case where we may want to surgically append/remove alerts from profile X, but I don't think it is critical to support this use case at this time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, so the primary use case is implemented by the module. The edge case of "surgically removing/appending" is not supported at the moment, but should be easy to add in the future if it'll ever be needed.

@jborean93 jborean93 removed the needs_triage Needs a first human triage before being processed. label Nov 1, 2017
- absent - alert profile should not exist,
- present - alert profile should exist,
- list - return a list of alert profiles.
required: False
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a blocker but required: False is the default, so no need to document it.

response = self.client.get(self.url + '?expand=alert_definitions,resources')
except Exception as e:
self.module.fail_json(msg="Failed to query alert profiles: {error}".format(error=e))
return response.get('resources', [])
Copy link
Contributor

Choose a reason for hiding this comment

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

If you like to replace None with [], it sugguest to change it to response.get('resources') or [] . The difference is, currently with this code, [] will only returned if there is no resources key in response

@ansibot ansibot removed the new_contributor This PR is the first contribution by a new community member. label Nov 2, 2017
@yaacov
Copy link
Contributor

yaacov commented Nov 2, 2017

shipit

Copy link
Contributor

@yaacov yaacov left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@cben cben left a comment

Choose a reason for hiding this comment

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

some technical comments. overall structure good.


EXAMPLES = '''
- name: List alert policies in ManageIQ
manageiq_alert_policies:
Copy link
Contributor

Choose a reason for hiding this comment

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

typo, manageiq_alert_profiles

default: 'present'
description:
description:
- The unique alert profile description in ManageIQ.
Copy link
Contributor

Choose a reason for hiding this comment

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

unique globally or within resource_type?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought it was globally unique, just like with alerts, but apparently alert profiles don't enforce uniqueness of the description. The module assumes its globally unique, but this is not necessarily true... I've sent an email to the relevant ManageIQ people to see if this can be changed.

Copy link
Contributor

Choose a reason for hiding this comment

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

So the new plan is to use name which is unique.
Creating from ansible, we can control both name and description.
Creating from UI only asks for description; it currently sets name to a GUID, will be changed to equal description.



# TODO: I copied this from yaacov's ansible/ansible PR 31233. It should be removed
# from here once that PR is merged.
Copy link
Contributor

Choose a reason for hiding this comment

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

now in utils, can drop from here.

self.module.fail_json(msg="Failed to query alert profiles: {error}".format(error=e))
return response.get('resources') or []

def get_alert_policies(self, alert_policies):
Copy link
Contributor

Choose a reason for hiding this comment

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

as discussed previously, no such thing "alert policies". every mention of "policy/ies" should be renamed...


# figure out which policies we need to assign / unassign
# alert polices listed by the user:
new_alert_policies = set(self.get_alert_policies(new_profile['alert_policies']))
Copy link
Contributor

Choose a reason for hiding this comment

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

"new" may sound as "to be added", suggest "desired" instead.

result = self.client.post(result['results'][0]['href'] + '/alert_definitions',
action="assign", resources=policies)
except Exception as e:
# TODO question - should we rollback the creation if assignment failed?
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO no need to.
Each step is idempotent, we failed to reach desired state but we got closer.
But mostly, it's just easier ;-)

"""
# find all alert policies to add to the profile
# we do this first to fail early if one is missing.
policies = [dict(href=href) for href in self.get_alert_policies(profile['alert_policies'])]
Copy link
Contributor

Choose a reason for hiding this comment

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

this dict(href=href) building repeats everywhere... can you move it inside either assign_or_unassign? or get_alert_policies()?

# now that it has been created, we can assign the policies
try:
result = self.client.post(result['results'][0]['href'] + '/alert_definitions',
action="assign", resources=policies)
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason not to use assign_or_unassign() here?

# existing profile has different notes
profile_dict['set_data'] = dict(notes=new_profile['notes'])

if new_profile['notes'] and ('set_data' not in old_profile or 'notes' not in old_profile['set_data']):
Copy link
Contributor

Choose a reason for hiding this comment

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

this condition, and previous one, are complicated.
partly caused by set_data asymmetry.
can you first compute 2 vars with existing notes and new notes (using None or '' where missing),
and then just check if old_notes != new_notes:?

Also, please open manageiq-api issues for each read vs write format asymmetry in the API. There are too many of these :-(

existing_profile = manageiq.find_collection_resource_by("alert_definition_profiles",
description=description)

# we need to add or update the alert policy
Copy link
Contributor

Choose a reason for hiding this comment

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

here again, and below L332, "alert policy" is not alert but typo for alert profile

@ansibot ansibot added the stale_ci This PR has been tested by CI more than one week ago. Close and re-open this PR to get it retested. label Nov 16, 2017
@jctanner
Copy link
Contributor

@cben can you re-review please?

if old_profile['set_data']['notes'] != new_profile['notes']:
# existing profile has different notes
profile_dict['set_data'] = dict(notes=new_profile['notes'])
old_notes = old_profile['set_data']['notes']
Copy link
Contributor

Choose a reason for hiding this comment

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

above 3 lines can be written as:

old_notes = old_profile.get('set_data', {}).get('notes')

old_notes = old_profile['set_data']['notes']

if desired_profile['notes'] != old_notes:
# existing profile has no notes, but we have notes
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this comment is not precise now, this also happens when existing has some old_notes, new has empty string, or both old/new non-empty but different... Can just drop it, or "# notes needs to be updated".

@elad661
Copy link
Contributor Author

elad661 commented Dec 20, 2017

I addressed review feedback and squashed the commits. Now that ManageIQ/manageiq-api#149 is merged, this module is ready for a final review (and eventually for being merged).

@cben @yaacov please take another look when you have the time.

@ansibot
Copy link
Contributor

ansibot commented Dec 20, 2017

The test ansible-test sanity --test no-assert [?] failed with the following error:

Command "test/sanity/code-smell/no-assert.py" returned exit status 1.
>>> Standard Output
Use of assert in production code is not recommended.
Python will remove all assert statements if run with optimizations
Alternatives:
    if not isinstance(value, dict):
        raise AssertionError("Expected a dict for value")
lib/ansible/modules/remote_management/manageiq/manageiq_alert_profiles.py:177:9:         assert action in ["assign", "unassign"]

click here for bot help

@ansibot ansibot removed community_review In order to be merged, this PR must follow the community review workflow. stale_ci This PR has been tested by CI more than one week ago. Close and re-open this PR to get it retested. labels Dec 20, 2017
alerts = []
for alert_description in alert_descriptions:
alert = self.manageiq.find_collection_resource_or_fail("alert_definitions",
description=alert_description)
Copy link
Contributor

@cben cben Dec 21, 2017

Choose a reason for hiding this comment

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

I think this should now match by name (and method arg should be named alert_names)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ignore this, I confused alert profile — matched by name, because that's the unique field — with alerts that are matched by description, which is unique in that table and more user friendly.

response = self.client.get(self.url + '?expand=alert_definitions,resources')
except Exception as e:
self.module.fail_json(msg="Failed to query alert profiles: {error}".format(error=e))
return response.get('resources') or []
Copy link
Contributor

Choose a reason for hiding this comment

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

python nitpick: if you just want to return [] for missing 'resource' key, write .get('resources', []).
As currently written is effectively .get('resource', None) or [], which will also accept "resources": null and other any "falsey" values like "resources": "". Harmless but one day someone will wonder "is this intentional, can server return non-arrays here?"...

Copy link
Contributor

Choose a reason for hiding this comment

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

oops this is exactly opposite to what @resmo recommended previously #32354 (comment)
I don't really care, LGTM from me on either form.

Copy link
Contributor

@cben cben left a comment

Choose a reason for hiding this comment

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

LGTM

@cben
Copy link
Contributor

cben commented Dec 21, 2017

shipit

@elad661
Copy link
Contributor Author

elad661 commented Dec 21, 2017

bot_status

@ansibot
Copy link
Contributor

ansibot commented Dec 21, 2017

Components

lib/ansible/modules/remote_management/manageiq/manageiq_alert_profiles.py
support: community
maintainers: abellotti cben gtanzillo yaacov zgalor

Metadata

waiting_on: maintainer
changes_requested_by: null
needs_info: False
needs_revision: False
needs_rebase: False
merge_commits: []
mergeable_state: clean
shippable_status: success
maintainer_shipits (module maintainers): 1
community_shipits (namespace maintainers): 0
ansible_shipits (core team members): 0
shipit_actors (maintainers or core team members): cben
shipit_actors_other: []

click here for bot help

@yaacov
Copy link
Contributor

yaacov commented Dec 21, 2017

shipit 🚢

@ansibot ansibot added shipit This PR is ready to be merged by Core and removed community_review In order to be merged, this PR must follow the community review workflow. labels Dec 21, 2017
@cben
Copy link
Contributor

cben commented Jan 4, 2018

@yaacov how can we move this and #32136 along?

Looks like bot ignored our shipits here? (I think we're "community_shipits (namespace maintainers)")
shipit

@yaacov
Copy link
Contributor

yaacov commented Jan 4, 2018

bot_status

@ansibot
Copy link
Contributor

ansibot commented Jan 4, 2018

Components

lib/ansible/modules/remote_management/manageiq/manageiq_alert_profiles.py
support: community
maintainers: abellotti cben gtanzillo yaacov zgalor

Metadata

waiting_on: maintainer
changes_requested_by: null
needs_info: False
needs_revision: False
needs_rebase: False
merge_commits: []
mergeable_state: clean
shippable_status: success
maintainer_shipits (module maintainers): 2
community_shipits (namespace maintainers): 0
ansible_shipits (core team members): 0
shipit_actors (maintainers or core team members): cben yaacov
shipit_actors_other: []

click here for bot help

@yaacov
Copy link
Contributor

yaacov commented Jan 4, 2018

LGTM 👍

@cben
Copy link
Contributor

cben commented Jan 4, 2018

@resmo could you review please?

@resmo
Copy link
Contributor

resmo commented Jan 4, 2018

LGTM

rebase_merge

Sorry to bother again

The module uses state=list, while there are some existing modules having a state=list, it is not something we accept anymore for new modules. This functionality should be implemented as a separate facts module.

@resmo
Copy link
Contributor

resmo commented Jan 4, 2018

needs_revision

@ansibot ansibot added needs_revision This PR fails CI tests or a maintainer has requested a review/revision of the PR. and removed shipit This PR is ready to be merged by Core labels Jan 4, 2018
@elad661
Copy link
Contributor Author

elad661 commented Jan 8, 2018

Okay, removed the state=list option.
@resmo @yaacov @cben, please take another look.

version_added: '2.5'
author: Elad Alfassa (ealfassa@redhat.com)
description:
- The manageiq_alert_profiles module supports listing, adding, updating and deleting alert profiles in ManageIQ.
Copy link
Contributor

Choose a reason for hiding this comment

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

listing ?

@yaacov
Copy link
Contributor

yaacov commented Jan 10, 2018

shipit

1 similar comment
@resmo
Copy link
Contributor

resmo commented Jan 10, 2018

shipit

@elad661
Copy link
Contributor Author

elad661 commented Jan 10, 2018

bot_status

@resmo
Copy link
Contributor

resmo commented Jan 10, 2018

merging.

@resmo resmo merged commit 8c87c76 into ansible:devel Jan 10, 2018
@resmo
Copy link
Contributor

resmo commented Jan 10, 2018

Thanks all of you for the hard work!

@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.5 This issue/PR affects Ansible v2.5 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. support:community This issue/PR relates to code supported by the Ansible community.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants