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

Avoid logging inside the varstack __virtual__ function #48436

Merged
merged 2 commits into from
Jul 12, 2018

Conversation

max-arnold
Copy link
Contributor

@max-arnold max-arnold commented Jul 4, 2018

What does this PR do?

Removes the [ERROR ] Can't find varstack master_top from logs when varstack is not used. This seems to be the recommended practice: https://docs.saltstack.com/en/latest/ref/modules/#logging-restrictions

Tests written?

No

Commits signed with GPG?

No

@max-arnold max-arnold requested a review from a team as a code owner July 4, 2018 09:20
@ghost ghost self-requested a review July 4, 2018 09:20
# Define the module's virtual name
__virtualname__ = 'varstack'


def __virtual__():
if not HAS_VARSTACK:
log.error("Can't find varstack master_top")
return False
return (False, 'The varstack master_tops plugin could not be loaded: varstack module not found.')
Copy link
Contributor

Choose a reason for hiding this comment

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

Parenthesis are extra here. Please remove them.

@@ -45,27 +45,20 @@

from __future__ import absolute_import, print_function, unicode_literals

# Import python libs
import logging

try:
HAS_VARSTACK = False
import varstack
HAS_VARSTACK = True
except ImportError:
pass

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 already doing this, then also please remove these HAS_FOO vars as well. As simple as that:

try:
    import varstack
except ImportError:
    varstack = None

def __virtual__():
    return bool(varstack), 'The varstack module could not be loaded: varstack dependency is missing.'

Note, I've updated the error message. Feel free to just copypaste all that. 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not quite the same. Original code returned __virtualname__ on success.

try:
HAS_VARSTACK = False
import varstack
HAS_VARSTACK = True
except ImportError:
pass

# Set up logging
log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'varstack'
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@isbm Why? The module does not use any logging, so I removed it.

@@ -31,16 +29,14 @@
except ImportError:
pass
Copy link
Contributor

Choose a reason for hiding this comment

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

try:
    import varstack
except ImportError:
    varstack = None

def __virtual__():
        return bool(varstack), 'message here...'

@@ -31,16 +29,14 @@
except ImportError:
pass

# Set up logging
log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'varstack'
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The module does not use any logging at all (or I'm missing something).

Copy link
Contributor

Choose a reason for hiding this comment

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

You do not need __virtualname__ if the filename is the same. You use it only in case the module is one of those like zypper/apt/yum/whatever but we refer to it as pkg. Please remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The module filename is varstack_pillar.py and __virtualname__ = 'varstack', so they are different.

Copy link
Contributor

@isbm isbm Jul 4, 2018

Choose a reason for hiding this comment

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

Srsly, I never understand why it is called that way. It is salt.pillar.varstack and salt.module.varstack. Why on Earth it needs to be called "Pizza pepperoni with meat pepperoni". Rename the file? Yes, I know there are other files like that. They are subject to rename too. 😉

Copy link
Contributor

Choose a reason for hiding this comment

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

I;ve just looked up. There are no imports, so it is safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also see https://github.com/saltstack/salt/blob/develop/salt/loader.py#L1789 (virtualname should match the returned value)

Copy link
Contributor

Choose a reason for hiding this comment

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

This is when you have it:
https://github.com/saltstack/salt/blob/develop/salt/loader.py#L1770

But if you return just True and your filename is properly named, it is fine.

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 have $SALT/modules/example.py:

def __virtual__():
    return True, 'Some error message'

def hello():
    return 'hello'

Then:

salt-call --local example.hello -l error
local:
    hello

But:

def __virtual__():
    return 'foo', 'Some error message'

...will render to this:

salt-call --local example.hello -l error
[ERROR   ] Failed to read the virtual function for module: example

And it won't even load the module.


# Define the module's virtual name
__virtualname__ = 'varstack'


def __virtual__():
if not HAS_VARSTACK:
return False
return (False, 'The varstack_pillar module could not be loaded: varstack module not found.')
Copy link
Contributor

Choose a reason for hiding this comment

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

Extra parenthesis. Please lookup the example in my other comments.

@max-arnold
Copy link
Contributor Author

Thanks for the feedback, I updated the PR (but not exactly as requested, see my questions above).

return __virtualname__
if varstack:
return __virtualname__
return False, 'The varstack_pillar module could not be loaded: varstack module not found.'
Copy link
Contributor

Choose a reason for hiding this comment

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

You do not need this. Please return just this:

return bool(varstack), '......

Your module is not any virtual, just True is totally sufficient. In case varstack is None, the error message next to it will be reused.


# Set up logging
log = logging.getLogger(__name__)
varstack = None

# Define the module's virtual name
__virtualname__ = 'varstack'
Copy link
Contributor

Choose a reason for hiding this comment

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

You need this only in case you want to rename the module and join it to some other group of those, like pkg for example. Otherwise keep it simple.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably document a standard. There is a mix of both styles at present.

return __virtualname__
if varstack:
return __virtualname__
return False, 'The varstack module could not be loaded: varstack dependency is missing.'
Copy link
Contributor

@isbm isbm Jul 4, 2018

Choose a reason for hiding this comment

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

Same as above. e=mc2 means "errors = more code ** 2" 😉

@max-arnold max-arnold force-pushed the develop branch 3 times, most recently from a6350ba to 6daa168 Compare July 4, 2018 14:10
@max-arnold
Copy link
Contributor Author

@isbm Done

doc/man/salt.7 Outdated
@@ -288913,7 +288913,7 @@ data to return as pillar information. From there you can take a look at the
varstack on how this file is evaluated.
.INDENT 0.0
.TP
.B salt.pillar.varstack_pillar.ext_pillar(minion_id, pillar, conf)
.B salt.pillar.varstack.ext_pillar(minion_id, pillar, conf)
Parse varstack data and return the result
.UNINDENT
Copy link
Contributor

Choose a reason for hiding this comment

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

You do not need to make changes to this file.

We regenerate it with each release from all of the other doc strings.

log.error("Can't find varstack master_top")
return False
return __virtualname__
return bool(varstack), 'The varstack module could not be loaded: varstack dependency is missing.'
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 need to return the virtual name when renamed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Technically that is not true in this case. When the __virtual__ returns True, the loader will fall back to the module name (i.e. without the .py). In this case, since it is called varstack.py, it would be loaded as varstack. So, it would work, though via a happy accident.

So it should still be changed to something like this:

if varstack is None:
    return (False, 'The varstack module could not be loaded: varstack dependency is missing.')
return __virtualname__

Note that the same change should be made to the external pillar module.

Copy link
Contributor

Choose a reason for hiding this comment

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

apparently my other comment didn't get posted.

I was also requesting that varstack.py gets renamed back to varstack_pillar.py, so that we do not run into the same problems we have seen with boto/boto3 and docker -> dockermod

Copy link
Contributor

@isbm isbm Jul 5, 2018

Choose a reason for hiding this comment

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

But this is really odd. Sounds to me like PHP problems: everything in one pile. Loader problems? Python has namespace, why is that now foo.bar.spam needs to clash with foo.fred.spam?

Guys, what I am missing here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, apparently I jumped over to the varstack tops file when reviewing and didn't realize it.

Copy link
Contributor

Choose a reason for hiding this comment

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

it isn't a problem with namespaces for modules.

It is a problem that we are doing import varstack inside this module.

https://github.com/saltstack/salt/pull/48436/files#diff-caa464e4e9ee6e852e118724583cc313L29

Copy link
Contributor

Choose a reason for hiding this comment

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

@terminalmage yeah, in that way it will crash for sure, as it doesn't use the namespace. How we can fix this (without randomising names of the components)? Enforce full import? Reject modules that are so? Other ideas? Because it is nicer to have salt.modules.docker and salt.pillar.docker instead of salt.modules.dockermodule and salt.pillar.docker_this_time_a_pillar.

Copy link
Contributor

Choose a reason for hiding this comment

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

@gtmanfred well, then just fix the import?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So it should still be changed to something like this:

if varstack is None:
    return (False, 'The varstack module could not be loaded: varstack dependency is missing.')
return __virtualname__

@terminalmage @gtmanfred This is basically what I did in my initial PR, but then changed it based on the feedback.

If necessary, I can resubmit my initial PR which was more idiomatic, as far as I can tell by looking at existing modules.

Copy link
Contributor

@isbm isbm Jul 6, 2018

Choose a reason for hiding this comment

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

@max-arnold OK, the loader seem has a problems that we need to tackle them later. The way it is now "fixed" is just that you don't have the same name in the module/pillars. And so when we have varstack in pillars, varstack in modules and varstack in Python, then things gets messy.

In that regard, lets do the following:

  • Rename (or leave?) salt.pillars.varstack_pillar
  • Rename salt.modules.varstackmod
  • varstack — comes from the Python
__virtualname__ = `varstack`

def __virtual__():
    return (varstack and __virtualname__ or False,
            'The varstack module could not be loaded: varstack dependency is missing.')

Then this should work. In a long run there should be either rules of the naming of the modules/pillars/states or a way to stop these sort of clashes.

@max-arnold
Copy link
Contributor Author

max-arnold commented Jul 9, 2018

  • Rebased to the latest develop branch
  • Renamed salt/tops/varstack.py to salt/tops/varstack_top.py (this way it seems to be more consistent with the corresponding pillar/varstack_pillar.py)
  • Dropped all documentation changes

return (
varstack and __virtualname__ or False,
'The varstack module could not be loaded: varstack dependency is missing.'
)
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks weird, what is it going to return? Why are we not just using.

if varstack is None:
    return False, 'The varstack module could not be loaded: varstack dependency is missing.'
return __virtualname__

Copy link
Contributor

@isbm isbm Jul 9, 2018

Choose a reason for hiding this comment

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

It is going to return __virtualname__ if varstack is a module, False otherwise. The error message is ignored if everything is OK.

Multiple returns considered bad style in Python, especially if you can avoid that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would still contend that the other way is more readable, but whatever

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you want me to change this part? I see several +1s, and actually, this is how it looked in my initial PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

you are fine. just waiting for @isbm to 👍 the review.


# Set up logging
log = logging.getLogger(__name__)
varstack = None

# Define the module's virtual name
__virtualname__ = 'varstack'
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably document a standard. There is a mix of both styles at present.

@cachedout
Copy link
Contributor

@isbm Are you OK with this as it sits right now?

Copy link
Contributor

@isbm isbm left a comment

Choose a reason for hiding this comment

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

@max-arnold Thanks!
@cachedout While we have to describe the __virtual* standard, we should make sure we are not enforcing workarounds for our monkeypatch problem in Loader, but we should first look there and fix it. We have import clashes and this is bad, and "just rename" is a workaround we would prefer to get rid of. Other then that yes, I am fine as it is now. But we should return to __virtual* topic soon.

@rallytime rallytime merged commit 9fbe6d5 into saltstack:develop Jul 12, 2018
@max-arnold
Copy link
Contributor Author

@rallytime I'm getting a warning on the latest develop branch during make -C doc clean html:

WARNING: [autosummary] failed to import u'salt.tops.varstack': no module named salt.tops.varstack

Not sure if this could be fixed by running apidoc-saltmods.sh (it fails for me with ./apidoc-saltmods.sh: 59: ./apidoc-saltmods.sh: 1: Dirname to exclude is required.), but it may be a good idea to add SPHINXOPTS = -W to doc/Makefile to turn any sphinx wanings into errors.

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

Successfully merging this pull request may close these issues.

6 participants