Nekmo / amazon-dash

Hack your Amazon Dash to run what you want.
MIT License
829 stars 67 forks source link

please add docker support #61

Closed crowland88 closed 6 years ago

crowland88 commented 6 years ago

please add docker suport

Nekmo commented 6 years ago

Ok

bachya commented 6 years ago

One note on thus far: when attempting to install and run this package in my own Docker container (and run it manually), I get this error (relating to the config file stored in a Docker volume):

Welcome to Amazon-dash v1.1.1 using Python 3.5.2
Listening for events. Amazon-dash will execute the events associated with the registered buttons.
Traceback (most recent call last):
  File "/usr/local/bin/amazon-dash", line 6, in <module>
    catch(cli)()
  File "/usr/local/lib/python3.5/dist-packages/amazon_dash/exceptions.py", line 91, in wrap
    return fn(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/amazon_dash/management.py", line 100, in run
    Listener(config).run(root_allowed=root_allowed)
  File "/usr/local/lib/python3.5/dist-packages/amazon_dash/listener.py", line 121, in __init__
    self.config = Config(config_path)
  File "/usr/local/lib/python3.5/dist-packages/amazon_dash/config.py", line 214, in __init__
    file=file, user=get_file_owner(file),
  File "/usr/local/lib/python3.5/dist-packages/amazon_dash/config.py", line 137, in get_file_owner
    return getpwuid(os.stat(file).st_uid)[0]
KeyError: 'getpwuid(): uid not found: 1000'

That KeyError needs to be caught and handled gracefully (or the underlying mechanism of Docker's root user ID needs to be dealt with in the container's construction).

Nekmo commented 6 years ago

I will increase the priority of this issue to include it in release 1.2.0

bachya commented 6 years ago

Thanks, @Nekmo! I have a good amount of experience in Dockerizing apps like yours, so if I may be of assistance, let me know!

Nekmo commented 6 years ago

Thank you @bachya! Can you do a pull request please? I don't have so much experience with docker.

bachya commented 6 years ago

You got it – once I have this running in a stable Docker, I’ll do a PR.

bachya commented 6 years ago

@Nekmo Starting down the road – you can find a simple, early Dockerfile in my fork: https://github.com/bachya/amazon-dash/blob/docker/Dockerfile

However, there are complications. No matter what configuration I use, I can't get my Dash Button to register. Hard to tell where the issue is – could be scapy having issues within a container, or it could be something else.

I'd love some help in testing (so that we can narrow down where the issue is). If you install Docker (available via most package managers), clone my fork, cd into it, and run these commands:

$ docker build -t nekmo/amazon-dash:latest .
$ docker run -it nekmo/amazon-dash:latest

...you should get a functioning container that immediately runs amazon-dash discovery.

Other variants of the run command that you can use:

# Reference: https://docs.docker.com/engine/reference/run/

# Run with "host" networking (i.e., networking equivalent to the host machine):
$ docker run -it --network=host nekmo/amazon-dash:latest

# Run in "privileged" mode:
$ docker run -it --privileged nekmo/amazon-dash:latest

# Use both:
$ docker run -it --privileged --network=host nekmo/amazon-dash:latest

If you can run these and tell me your results, we can narrow down whether the issues exists in my networking or within the Docker setup.

Nekmo commented 6 years ago

@bachya there is an option to choose the network interface in Amazon-dash. Maybe this option can help you.

https://github.com/Nekmo/amazon-dash/blob/develop/amazon_dash/management.py#L121

related issue: https://github.com/Nekmo/amazon-dash/issues/55

Thanks for your help

bachya commented 6 years ago

~Unfortunately, using different network interfaces inside the container don't produce a difference. Are you able to help run the above commands? That will help me isolate where the issue is.~

After some testing, I'm able to sniff my devices when directly using scapy – so, the issue lies within Docker's networking stack. Not my area of expertise, sadly, but I'll keep digging.

davosian commented 6 years ago

Not sure whether it is of any help, but I just came across another Amazon Dash implementation on Docker Hub that is using scapy (successfully?): https://github.com/vwieczorek/amazon-dash-docker/blob/master/Dockerfile

bachya commented 6 years ago

@davosian Appreciate the help. Unfortunately, that Dockerfile doesn't tell us anything about how he got the host networking interfacing with the container network (such that packet inspection becomes available). Continuing to dig.

bachya commented 6 years ago

GOT IT.

Preamble: as we might expect, we need a way for the container to access the host's network to do packet inspection. There are many "better" ways to do this, but the manner I'm going to suggest is to give the container the --network=host option. It's easy and doesn't require creating bridge networks, etc. (which is way too much to put on amazon-dash users).

I was attempting to test this on my Mac. Took me way, way too long to learn that --network=host doesn't work as expected on Mac.

Once I tested my Dockerfile on a Linux host, what do you know, everything started working:

/usr/src/app # amazon-dash discovery
Welcome to Amazon-dash v1.2.0a1 using Python 2.7.15
The discovery command lists the devices that are connected in your network. Each device will only be listed once. After executing this command wait approximately 10 seconds before pressing the Amazon Dash button. After pressing the button, the Mac address of the button will immediately appear on the screen. Remember the address to be able to create the configuration file.
b8:e9:37:a7:07:54

b8:ae:ed:7f:fd:6f
fc:ec:da:45:f6:20
fc:ec:da:31:aa:47
18:74:2e:fc:f0:ab (Amazon Device)
8c:85:90:b2:c1:b5
5c:aa:fd:15:6f:ca

!!!

So, long story short: we are unblocked and progressing

Nekmo commented 6 years ago

I don't have so much experience in Docker to be able to help, I'm sorry. My efforts are now in Amazon-dash 2.0.

If I have time I will look for documentation to help with this task.

bachya commented 6 years ago

No worries, @Nekmo – I'm making good progress. I'll make sure to include instructions in my PR.

davosian commented 6 years ago

@bachya Had I known... I ran into the --network=host issue on my Mac before. Let me know if you need someone to test. I am following along since my goal is to have a docker image for Amazon Dash to integrate it into my Home Assistant installation (which is itself running as docker container on Ubuntu using --network=host).

bachya commented 6 years ago

@davosian No problem! I'm in very good shape: currently have HASS and amazon-dash running in separate containers, happy as clams. :) I'll publish a PR soon and would love to have you test!

bachya commented 6 years ago

@Nekmo PR submitted! https://github.com/Nekmo/amazon-dash/pull/77

@davosian If you'd like to help test, I'm temporarily hosting the Docker image (until the official one gets up and running): https://hub.docker.com/r/bachya/amazon-dash/

Nekmo commented 6 years ago

@bachya the pull requests have been verified and accepted :+1:

I have to check that it works. Thank you!

susadmin commented 6 years ago

I would like to test your docker image but am having a few issues:

  1. Can you tell me where the config file shoud be placed?
  2. Should it still be called amazon-dash.yml?
  3. Can you give the docker run command line you used to start the container?

Thanks!

bachya commented 6 years ago

@susadmin Absolutely – put those instructions in the docs, but forgot to put them here for testing.

  1. Can you tell me where the config file shoud be placed?

It can be placed anywhere; we will map it into the container below.

  1. Should it still be called amazon-dash.yml?

Can be called whatever you like.

  1. Can you give the docker run command line you used to start the container?
$ docker run -it --network=host -v <path/to/amazon-dash.yml>:/config/amazon-dash.yml bachya/amazon-dash:latest amazon-dash run --config /config/amazon-dash.yml
susadmin commented 6 years ago

There seems to be a problem. I have the app running fine in a docker container. It responds to the button press but then throws an error. Here is the log:

Welcome to Amazon-dash v1.2.0a1 using Python 2.7.15

Listening for events. Amazon-dash will execute the events associated with the registered buttons.

Exception in thread Thread-1:

Traceback (most recent call last):

  File "/usr/local/lib/python2.7/threading.py", line 801, in __bootstrap_inner

    self.run()

  File "/usr/local/lib/python2.7/threading.py", line 754, in run

    self.__target(*self.__args, **self.__kwargs)

  File "/usr/local/lib/python2.7/site-packages/amazon_dash/listener.py", line 84, in execute

    result = self.execute_instance.execute(root_allowed)

  File "/usr/local/lib/python2.7/site-packages/amazon_dash/execute.py", line 215, in execute

    raise ExecuteError('Exception on request to {}: {}'.format(self.data['url'], e))

ExecuteError: Exception on request to https://<ip addr>/api/services/light/toggle: HTTPSConnectionPool(host='<addr>ip', port=443): Max retries exceeded with url: /api/services/light/toggle (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f00a808d490>: Failed to establish a new connection: [Errno 113] Host is unreachable',))

I can ping (my docker home assistant app) fine. With curl, this works: curl -X POST -H "Content-Type: application/json" -d '{"entity_id": "light.office"}' https://<ip addr>/api/services/light/toggle

Here is my config.yml:

settings:
  delay: 2
devices:
  6C:56:97:1F:D7:A1:
    name: Finish
    url: 'https://<ip addr>/api/services/light/toggle'
    method: post
    content-type: json
    body: '{"entity_id": "light.office"}'

Do you have ideas on what is going wrong?

bachya commented 6 years ago

@susadmin Does that configuration work when Amazon Dash is run outside of Docker?

susadmin commented 6 years ago

Yes, it works no problem

bachya commented 6 years ago

The Host is unreachable message means that the container can’t reach the HASS container. Hard to tell why without more info.

When you say you can ping the HASS container, is that from the Amazon Dash container? Are both using --network=host?

susadmin commented 6 years ago

Yes, I am using --network=host in my docker run command line.

My HASS container has its own dedicated lan ip I have setup with a macvlan network. The HASS container does not repsond to pings but the amazon-dash container does correctly resolve ip address if I test it through its shell. I am using the exact same amazon-dash.yml file in both container and standalone version. Standalone works fine.

Update: I have done a little playing around with network settings and I find if I use --network=macvlan (the same network the HASS container is on and part of my lan /24 subnet) it works fine! Funny though, because I have other containers using the host network which work perfectly.

Maybe there is something super sensitive with the network implementation?

bachya commented 6 years ago

Very possible. Docker's networking options are vast, varied, and beyond me, so glad you got it working.

susadmin commented 6 years ago

Thanks for all your help! I am pretty new to docker and am in the process of converting as many of my apps as I can. It's a steep learning curve.

I do think dockerising amazon-dash is a really good idea. Hopefully, it can be integrated with Nekmo's work. So please do let me know if there is anything I can do to help the cause.

Nekmo commented 6 years ago

Network works for me in Linux without change config :+1:

susadmin commented 6 years ago

Yes, it works for me too in linux with no config change; it's just the netfig config of the docker container that is a bit finickity.

Nekmo commented 6 years ago

Ok, I think everything is ready. Thanks to @bachya

davosian commented 6 years ago

I can confirm that the docker container from nekmo is working fine in concert with my HASS container. I was using the following docker-compose file (@Nekmo feel free to include in the docker instructions):

version: '3.7'
services:
  dash:
    image: nekmo/amazon-dash
    container_name: dash
    volumes:
      - </full/path/path/to/config/folder>:/config
    restart: unless-stopped
    network_mode: host
    command: amazon-dash run --ignore-perms --root-allowed --config /config/amazon-dash.yml
    # command: amazon-dash discovery

To use this with docker, run docker-compose up -d and check the log with docker-compose logs -f dash. To run the discovery first, uncomment the other command line instead (only one of them should be uncommented at the same time).

Please note that I am mapping the config folder and not the amazon-dash.yml file directly. The reason for this is a weird behavior on the docker side: if you map the amazon-dash.yml file directly when it does not exist yet, docker creates a folder with the name of amazon-dash.yml instead.

Also please note: docker installation instructions are still missing from the manual pages: http://docs.nekmo.org/amazon-dash/installation.html

@bachya @Nekmo Great job, thanks to you both!

Nekmo commented 6 years ago

Support for Docker is still experimental and is in the develop branch. The documentation will be updated with release 1.2.0 :)

@davosian I will update with Dockerfile setting Python 3.7 and update the documentation. Thank you :)

bachya commented 6 years ago

@Nekmo Not sure if you saw my note on the PR re: my managing the Docker Hub repo; let me know how you'd like to proceed?

Nekmo commented 6 years ago

@bachya Yes I have seen your comment :) I need time to see how to add a co-owner. Sorry for the wait.

Nekmo commented 6 years ago

@bachya As I understand it, I need to create an organization to add a co-owner. This is correct?

bachya commented 6 years ago

@Nekmo I’m not sure that’s necessary. If you add me as a collaborator (under Settings), I think that’ll get us what we need. If you don’t mind, let’s try that first.

Nekmo commented 6 years ago

@bachya You are already a collaborator. Can you try? Thanks! :D

bachya commented 6 years ago

Yes, got it! I'll start setting things up and will keep you posted. 👍

bachya commented 6 years ago

@Nekmo Just attempted to link a Docker job to this repo and got this message: "The repository name nekmocom/amazon-dash is already taken."

Have you already set up a Docker Hub account?

Nekmo commented 6 years ago

@bachya I created nekmocom to do a test. I have added you as a co-owner in this test repository.

bachya commented 6 years ago

What's the difference between these two?

  1. https://hub.docker.com/r/nekmo/amazon-dash/
  2. https://hub.docker.com/r/nekmocom/amazon-dash/

It looks like #1 is already set up and pretty much good to go?