tomaae / homeassistant-portainer

Portainer integration for Home Assistant
Apache License 2.0
88 stars 7 forks source link

[Feature] Start/Stop/Restart Container possibility ? #9

Open Raynoxis opened 1 year ago

Raynoxis commented 1 year ago

Hello,

Thank you very much for your work.

Do you think it would be possible to add the ability to start/stop/restart a container?

Thank you very much,

Gaeku

marcokreeft87 commented 1 year ago

I would love this feature. And also cpu/memory usage would be awesome

tomaae commented 1 year ago

that will of course be implemented. I didnt expected people to find this integration before it will be added to HACS :)

marcokreeft87 commented 1 year ago

You underestimate the power of the internet haha

mhinke commented 11 months ago

Thank you for the integration,

future request is: start/ stop containers (and the cpu/memory load).

Tscherno commented 9 months ago

Hi,

i'm yearningly waiting for this feature. At the moment i created a bunch of ugly shell_commands with SSH for that.

Zen3515 commented 8 months ago

Forget about waiting, just add this into your config. I've been using this api for years, it should be quite stable

portainer_generic:
  rest_command:
    turn_on_stack:
      # require
      #   - stack_id
      url: https://portainer.com/api/stacks/{{ stack_id }}/start?endpointId={{ endpoint_id }}
      method: POST
      headers:
        x-api-key: YOUR_API_KEY
      payload: '{"id": "{{ stack_id }}","endpointId": "{{ endpoint_id }}"}'
    turn_off_stack:
      # require
      #   - stack_id
      #   - endpoint_id
      url: https://portainer.com/api/stacks/{{ stack_id }}/stop?endpointId={{ endpoint_id }}
      method: POST
      headers:
        x-api-key: YOUR_API_KEY
      payload: '{"id": "{{ stack_id }}","endpointId": "{{ endpoint_id }}"}'
    restart_container:
      url: https://portainer.com/api/endpoints/{{ endpoint_id }}/docker/containers/{{ container_id }}/restart
      method: POST
      headers:
        x-api-key: YOUR_API_KEY
      payload: "{}"
    start_container:
      url: https://portainer.com/api/endpoints/{{ endpoint_id }}/docker/containers/{{ container_id }}/start
      method: POST
      headers:
        x-api-key: YOUR_API_KEY
      payload: "{}"
    stop_container:
      url: https://portainer.com/api/endpoints/{{ endpoint_id }}/docker/containers/{{ container_id }}/stop
      method: POST
      headers:
        x-api-key: YOUR_API_KEY
      payload: "{}"

And here is my example of how I start/stop stack, restart container

portainer_cups_stacks:
  sensor:
    - platform: rest
      name: Cups Stack Status
      headers:
        x-api-key: YOUR_API_KEY
      json_attributes:
        - Name
        # - SwarmId
        - Id
        - EndpointId
        - UpdateDate
      value_template: >-
        {% set state_lookup = {
          0: 'starting',
          1: 'running',
          2: 'off',
          99: 'unavailable',
        } %}
        {{ state_lookup[(value_json['Status'] | default('99') | int)] }}
      resource: https://portainer.com/api/stacks/28
  template:
    - binary_sensor:
        - name: Cups Stack
          state: >-
            {{ is_state('sensor.cups_stack_status', 'running') }}
          device_class: running
    # - sensor:
    #     - name: Cups Stack Update Date
    #       state: >-
    #         {% set update_date = state_attr('sensor.cups_stack_status', 'UpdateDate') %}
    #         {% if (update_date or false ) != false -%}
    #         {{ state_attr('sensor.cups_stack_status', 'UpdateDate') | as_datetime | as_local }}
    #         {%- else -%}
    #         {{ 'unavailable' }}
    #         {%- endif %}
    #       availability: >-
    #         {{ state_attr('sensor.cups_stack_status', 'UpdateDate') or false }}
    #       icon: mdi:timeline-clock-outline
  switch:
    - platform: template
      switches:
        cups_stack:
          value_template: "{{ is_state('sensor.cups_stack_status', 'running') }}"
          turn_on:
            - service: rest_command.turn_on_stack
              data:
                stack_id: "{{ state_attr('sensor.cups_stack_status', 'Id') | default(-1) }}"
                endpoint_id: "{{ state_attr('sensor.cups_stack_status', 'EndpointId') | default(-1) }}"
            - delay:
                seconds: 5
                milliseconds: 500
            - service: homeassistant.update_entity
              target:
                entity_id: sensor.cups_stack_status
          turn_off:
            - service: rest_command.turn_off_stack
              data:
                stack_id: "{{ state_attr('sensor.cups_stack_status', 'Id') | default(-1) }}"
                endpoint_id: "{{ state_attr('sensor.cups_stack_status', 'EndpointId') | default(-1) }}"
            - delay:
                seconds: 1
                milliseconds: 500
            - service: homeassistant.update_entity
              target:
                entity_id: sensor.cups_stack_status
          availability_template: >-
            {{ (state_attr('sensor.cups_stack_status', 'Id') | default(-1)) != -1 }}
          icon_template: >-
            {% if is_state('sensor.cups_stack_status', 'running') %}
              mdi:toggle-switch
            {% else %}
              mdi:toggle-switch-off-outline
            {% endif %}

portainer_cups_container:
  sensor:
    - platform: rest
      name: Cups Container State
      icon: "mdi:calendar-clock"
      headers:
        x-api-key: YOUR_API_KEY
      json_attributes_path: "$.[0]"
      json_attributes:
        - State
        - Status
        - Created
        - Id
      value_template: "{{ value_json[0].State }}" #"{{ value_json['Created'] | as_datetime | as_local }}"
      params:
        all: true
        filters: '{"label":["com.docker.compose.service=cups"]}'
      resource: https://portainer.com/api/endpoints/2/docker/containers/json
  template:
    - button:
        - unique_id: cups_container_restart
          name: >-
            {% if is_state('sensor.cups_container_state', 'running') %}
              Restart Cups Server
            {% else %}
              Start Cups Server
            {% endif %}
          icon: >-
            {% if is_state('sensor.cups_container_state', 'running') %}
              mdi:restart
            {% else %}
              mdi:play-circle-outline
            {% endif %}
          press:
            - service: rest_command.restart_container
              data:
                container_id: "{{ state_attr('sensor.cups_container_state', 'Id') | default(-1) }}"
                endpoint_id: "2"
            - delay:
                seconds: 2
                milliseconds: 500
            - service: homeassistant.update_entity
              target:
                entity_id:
                  - sensor.cups_container_state
                  # - sensor.cups_container_status
    - sensor:
        - name: Cups Container Status
          state: "{{ state_attr('sensor.cups_container_state', 'Status') }}"
          availability: >-
            {{ (state_attr('sensor.cups_container_state', 'Status') | default('None')) != 'None' }}
          icon: mdi:calendar-start
Domi2805 commented 5 months ago

Could someone please explain in which config file I need to enter this? If I put it into the configuration.yaml, I get the following error: Integration error: portainer_cups_stacks - Integration 'portainer_cups_stacks' not found and Integration error: portainer_cups_container - Integration 'portainer_cups_container' not found. Im on Version 2024.3.0.

Thank you.

Zen3515 commented 5 months ago

Could someone please explain in which config file I need to enter this? If I put it into the configuration.yaml, I get the following error: Integration error: portainer_cups_stacks - Integration 'portainer_cups_stacks' not found and Integration error: portainer_cups_container - Integration 'portainer_cups_container' not found. Im on Version 2024.3.0.

Thank you.

It's quite hard to keep track of the yaml file if you have many things you wrote it yourself. That's why I use include_dir_named packages

homeassistant:
  packages: !include_dir_named packages

So, in the example I provided, there are three yaml file

It was used just to organize the yaml file.

You technically could merge the tree file inside your configuration.yaml, it's just that I find it hard to track. To do that, you have to place each section to the correct place or read the doc I mentioned earlier to wrote packages as inline instead.

You also need to understand how it works, first it have scrape sensor to find out your container id or stack id, so thay it could use rest command to start or stop it. So, you need to modify it accordingly.

Domi2805 commented 5 months ago
/api/endpoints/2/docker/containers/json

So, I've created all the .yaml files like you did, changed the URLs to my local server, and filled in the API keys, and now I've got this. Screenshot 2024-03-17 After I press 'Start Cups Server', I see a last-used timestamp on my API key in Portainer, but nothing is changing.

Zen3515 commented 5 months ago

My container is cups

But in your case, you'll have to adjust it to your stack/container.

Like in Cups Container State It fetch from stack number 2, you'll have to change it to your stack, and the way to filter/extract your container information.

Essentially, you could take a look at dev tool when you restart the container from your portainer website, that's probably the easiest way for you to understand the parameters needed for it.

Domi2805 commented 5 months ago

My container is cups

But in your case, you'll have to adjust it to your stack/container.

Like in Cups Container State It fetch from stack number 2, you'll have to change it to your stack, and the way to filter/extract your container information.

Essentially, you could take a look at dev tool when you restart the container from your portainer website, that's probably the easiest way for you to understand the parameters needed for it.

Thank you, got it working now!

fufurax commented 5 months ago

Forget about waiting, just add this into your config. I've been using this api for years, it should be quite stable

Hi,

Thanks for your examples, I've create 2 rest command to to start/stop my container.

Is there a way to create a sensor to get periodically the status on a container (not a stack).

Tks

Zen3515 commented 5 months ago

Forget about waiting, just add this into your config. I've been using this api for years, it should be quite stable

Hi,

Thanks for your examples, I've create 2 rest command to to start/stop my container.

Is there a way to create a sensor to get periodically the status on a container (not a stack).

Tks

I believed that you could just use dev tools on the page that you want and replicate it on your rest sensor.

That's what I did to fetch contain status

portainer_cups_container:
  sensor:
    - platform: rest
      name: Cups Container State
      icon: "mdi:calendar-clock"
      headers:
        x-api-key: YOUR_API_KEY
      json_attributes_path: "$.[0]"
      json_attributes:
        - State
        - Status
        - Created
        - Id
      value_template: "{{ value_json[0].State }}" #"{{ value_json['Created'] | as_datetime | as_local }}"
      params:
        all: true
        filters: '{"label":["com.docker.compose.service=cups"]}'
      resource: https://portainer.com/api/endpoints/2/docker/containers/json
fufurax commented 5 months ago

Thanks, but if the container is stopped there is nothing in the json for this container. So return value will be empty ?

I've the following error message 👍

Template variable error: dict object has no element 0 when rendering '{{ value_json[0].State }}'

alx-xlx commented 1 month ago

Just wondering if the Control part is going to be implemented or not. or will I have to depend upon this workaround