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

fire_event() code call does not seem to work for me #8849

Closed
wari opened this issue Nov 27, 2013 · 21 comments
Closed

fire_event() code call does not seem to work for me #8849

wari opened this issue Nov 27, 2013 · 21 comments
Labels
Bug broken, incorrect, or confusing behavior fixed-pls-verify fix is linked, bug author to confirm fix Regression The issue is a bug that breaks functionality known to work in previous releases. severity-low 4th level, cosemtic problems, work around exists

Comments

@wari
Copy link
Contributor

wari commented Nov 27, 2013

I've been following the documentation @ http://docs.saltstack.com/topics/event/index.html

So, I have the event listener code running on the master side, and it's happily returning events as I got them via iter_events(full=True) call.

Now to fire events from any minions!

salt-call event.fire_master 'message for the master' 'tag'

Yup, that works.

import salt.utils.event
sock_dir = '/var/run/salt/minion'
payload = {'sample-msg': 'this is a test'}
event = salt.utils.event.SaltEvent('master', sock_dir)
event.fire_event(payload, 'tag')

This however, does not work, nothing seems to happen. I tried changing 'master' to the actual master id, or event the minion id, but still, I see nothing coming through the event bus. I'm running the code on other minions as well as minion that is running on the master server. Anything else I might forget?

@basepi
Copy link
Contributor

basepi commented Nov 27, 2013

What version of salt are you using?

@wari
Copy link
Contributor Author

wari commented Nov 28, 2013

@basepi same machines as #8845

               Salt: 0.17.2
             Python: 2.7.3 (default, Sep 26 2013, 20:03:06)
             Jinja2: 2.6
           M2Crypto: 0.21.1
     msgpack-python: 0.1.10
       msgpack-pure: Not Installed
           pycrypto: 2.4.1
             PyYAML: 3.10
              PyZMQ: 13.0.0
                ZMQ: 3.2.2

@basepi
Copy link
Contributor

basepi commented Dec 2, 2013

Thanks. It definitely seems like it should be working. Any chance you'd be willing to test on the current develop branch?

@wari
Copy link
Contributor Author

wari commented Dec 3, 2013

@basepi I still get the same results with version 0.17.0-5250-g86c8a5c, that is, the command line works, but doing it via code, nothing happens.

Code on master:

import salt.utils.event

event = salt.utils.event.MasterEvent('/var/run/salt/master')

for data in event.iter_events(full=True):
    print(data)

code on minion (remote and local to master):

# Import the proper library
# pasted from the docs
import salt.utils.event
# Fire deploy action
sock_dir = '/var/run/salt/minion'
payload = {'sample-msg': 'this is a test',
           'example': 'this is the same test'}
event = salt.utils.event.SaltEvent('master', sock_dir)
event.fire_event(payload, 'tag')

Both code runs as root user, event.fire_event() returns True. The command line takes a long time to response, and from the event bus, 3 items got sent, 2 are tagged 'salt/auth', and the third one is the actual data. event.fire_event() returns True immediately.

@basepi
Copy link
Contributor

basepi commented Dec 3, 2013

Right, the auths are expected, I think -- part of salt-call. I know @SmithSamuelM has been heavily involved in the way events have changed recently (with his work on the reactor and halite) -- I'll check with him tomorrow and see if he has any ideas.

@SmithSamuelM
Copy link
Contributor

Currently fire_event is not being passed via a 0MQ to the master but is calling directly to the master this means
it will only work if the permission of the user running the api allow it. Consequently there is not yet authentication for fire_event. other than the user permissions. I believe there is an issue on this somewhere. So if you run the api as root it will work. The real fix is to change fire_event so that it sends a master_call (like the run api call) over zero mq which is authenticated.

@wari
Copy link
Contributor Author

wari commented Dec 4, 2013

@SmithSamuelM when you said:

this means it will only work if the permission of the user running the api allow it.

and

So if you run the api as root it will work.

It does not work at all, I ran both code as the root user and it did not get captured into the event bus. This is particularly worrisome as I'd like to have a program that is outside of salt being able to send out a distress signal to the master via code.

If this is supposed to be done a different way, I don't mind it much but the documentation, as it stands now, is not correct.

@SmithSamuelM
Copy link
Contributor

There may be a bug somewhere that has broken it. We will look into it. Thanks for trying this out.

@olliewalsh
Copy link
Contributor

@wari I believe you'll also need to use the same sock_dir for the event sender and listener

@wari
Copy link
Contributor Author

wari commented Dec 18, 2013

@olliewalsh how do I send an event to the master from a minion that's on another host via the API? Definitely they don't share the same sock_dir.

@olliewalsh
Copy link
Contributor

@wari I think what @SmithSamuelM was saying is that it's using an IPC socket on the filesystem, not a TCP socket. So you can use the API to send minion events on the minion or to send master events on the master.

To send a master event from a minion you would need to replicate what the minion does:

def fire_master(data, tag, preload=None):

IIRC this sends an event to the event publisher on the master which relays this to the master IPC socket.

Running salt-api on the master might be the way to go. It gives a REST interface to the master event system but it appears to be read only at the moment. Adding support for sending should be straightforward I think.

@wari
Copy link
Contributor Author

wari commented Dec 30, 2013

Hi, sorry for the late reply. Ok, I'm trying to do my own event sender from a minion. Based on modules/event.py I tried to do a simple call, and here's what I got so far:

import salt.crypt
import salt.utils
import salt.payload.event
import salt.config

__opts__ = salt.config.minion_config('/etc/salt/minion')
auth = salt.crypt.SAuth(__opts__)

So this is where it borks:

KeyError                                  Traceback (most recent call last)
/root/<ipython-input-10-4d66448eaeb7> in <module>()
----> 1 auth = salt.crypt.SAuth(__opts__)

/usr/lib/python2.7/dist-packages/salt/crypt.pyc in __init__(self, opts)
    444     def __init__(self, opts):
    445         super(SAuth, self).__init__(opts)
--> 446         self.crypticle = self.__authenticate()
    447 
    448     def __authenticate(self):

/usr/lib/python2.7/dist-packages/salt/crypt.pyc in __authenticate(self)
    456             creds = self.sign_in(
    457                 self.opts.get('_auth_timeout', 60),
--> 458                 self.opts.get('_safe_auth', True)
    459             )
    460 

/usr/lib/python2.7/dist-packages/salt/crypt.pyc in sign_in(self, timeout, safe)
    294 
    295         sreq = salt.payload.SREQ(
--> 296             self.opts['master_uri'],
    297         )
    298         try:

KeyError: 'master_uri'

So how do I get master_uri to be populated properly? I believe if I do get that right. I should be on my way to sending my own events.. Thanks.

@cachedout
Copy link
Contributor

Hi @wari. I think @cro might have fixed this the other day in #9487. Could you pull down his change and see if it corrects your issue? Thanks!

@wari
Copy link
Contributor Author

wari commented Jan 2, 2014

Hi @cachedout, pulled the changes, and tested. Master URI is there, but I think it points to the wrong IP:

In [46]: cfg = salt.config.client_config('/etc/salt/minion')                                         

In [47]: cfg['master_uri']
Out[47]: 'tcp://127.0.0.1:4506'

Anyway, further on, I've even changed it to cfg['master_uri'] = 'tcp://192.168.122.44:4506' but still not good. The master_uri error is out, but others appear:

First, cfg['master'] is not there.. I set it to the master ip, not good, error is SaltClientError: Could not access /etc/salt/pki/master. Path does not exist.. Changing this to minion_master or minion kept that error quiet. Then there's another issue after that, specifically time.sleep(self.opts['acceptance_wait_time']), no acceptance_wait_time. So I randomly set this to 1, which finally causes the auth = salt.crypt.Sauth(cfg) to hang. I'm sure the cfg dict is not properly filled up yet.

Again, there must be an easier way to send out events programmatically in python. And I don't mean os.system("salt-call event.fire_master '{\"foo\":\"bar\"}' 'tag'") even though that works right now.

@cachedout
Copy link
Contributor

Hi again @wari

Apologies for the delay in responding to this.

To get right to the point, here is some code that works for me when run on the minion as root. Note that if the key is unaccepted for the given ID, you may need to accept it using salt-key or it will hang after the API request.

Obviously, you can just go ahead and replicate the very basic steps present in StateFire() but I just used it for convenience here.

import salt.utils.event
import salt.config
import pprint

opts = salt.config.client_config('/etc/salt/minion')
pprint.pprint(opts)
opts['id'] = 'silver'
opts['acceptance_wait_time'] = 5

payload = {'sample-msg': 'this is a test'}

sf = salt.utils.event.StateFire(opts)
sf.fire_master(payload, 'tag')

On the master, using event_listen.py, you'll see the following on the event bus:

Event fired at Thu Feb  6 10:07:27 2014
*************************
Tag: salt/auth
Data:
{'_stamp': '2014-02-06_10:07:27.383660',
 'act': 'accept',
 'id': 'silver',
 'pub': '-----BEGIN PUBLIC KEY-----\nhkiG9w0BAQEFAAOCAAgEAnG0EZ5GtodyfRI3ySHoB\ngEBCpen/z
<snip_key>
-----END PUBLIC KEY-----\n',
 'result': True}
Event fired at Thu Feb  6 10:07:27 2014
*************************
Tag: tag
Data:
{'_stamp': '2014-02-06_10:07:27.604302',
 'cmd': '_minion_event',
 'data': {'sample-msg': 'this is a test'},
 'id': 'silver',
 'tag': 'tag'}

Note that if the 'act' argument in the key event is pending that you'll need to accept the key before continuing. Of course, you can (and probably should) also set acceptance_wait_time in the minion config. I'm not certain right now why acceptance_wait_time isn't using the default from config.py. That could be a bug.

@wari
Copy link
Contributor Author

wari commented Feb 25, 2014

Hi there @cachedout sorry for the late reply, on sf = salt.utils.event.StateFire(opts), I get a KeyError when it's looking for self.opts['master'].

>>> sf = salt.utils.event.StateFire(opts)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/pymodules/python2.7/salt/utils/event.py", line 602, in __init__
    self.auth = salt.crypt.SAuth(self.opts)
  File "/usr/lib/pymodules/python2.7/salt/crypt.py", line 502, in __init__
    self.crypticle = self.__authenticate()
  File "/usr/lib/pymodules/python2.7/salt/crypt.py", line 514, in __authenticate
    self.opts.get('_safe_auth', True)
  File "/usr/lib/pymodules/python2.7/salt/crypt.py", line 335, in sign_in
    self.opts['master'],
KeyError: 'master'

Also, does client_config not get the ['id'] if it's located in the minion.d/*.conf directory?

@whiteinge
Copy link
Contributor

@wari you might have an easier time going through the Python class for salt-call instead:

import salt.client
caller = salt.client.Caller('/etc/salt/minion')
caller.sminion.functions['event.fire_master']({'foo': 'Foo!'}, 'my/custom/tag')

@wari
Copy link
Contributor Author

wari commented Feb 26, 2014

@whiteinge thanks a lot! This works nicely (and easier too!). Does this work with auth tokens? I guess not, as only the master has external-auth items. What I mean is that if I can do it in this way programmatically, I would need to have something that runs as root to do the calls, or program a kind of communication bridge, either via http, or a setuid type of program.

@whiteinge
Copy link
Contributor

@wari You're right this doesn't work with auth for the reasons you specified.

If you need auth and can/want to do this via HTTP you may be interested in this webhook addition to salt-api. I'll be cutting a release with that addition soon.

@cachedout
Copy link
Contributor

Hi @wari. Does @whiteinge 's suggestion allow us to close this issue? If there are remaining bugs to be worked out, we can certainly handle them but we'd like to get this closed if there's no additional bugs to be worked on. Thanks!

@wari
Copy link
Contributor Author

wari commented Mar 6, 2014

@whiteinge and @cachedout, thanks for your help, I would actually consider this closed if the documentation points out the way to fire events from the minions -> http://docs.saltstack.com/topics/event/index.html <- this one still won't work. Using salt-call functions as a work around works great for me, except that I have a feeling that the API might change. Using the webhooks as recommended by @whiteinge is one way to get an app send an event, but I believe the salt-api needs to sit on the master right? Minions have direct access to master, but for apps having access to master via salt-api is a no-go as there will be too many variables to configure.

I can only see myself using a simple flask based app running on localhost (or file socket) as root to talk fire events using the salt-call function with my apps. So I'm wishing for a couple of things here.

  • Updated docs
  • A way to do salt-call on a minion without the need for root (thru eauth?)

Anyway, I'll close the issue.. Thanks guys,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug broken, incorrect, or confusing behavior fixed-pls-verify fix is linked, bug author to confirm fix Regression The issue is a bug that breaks functionality known to work in previous releases. severity-low 4th level, cosemtic problems, work around exists
Projects
None yet
Development

No branches or pull requests

6 participants