homeassistant-portainer icon indicating copy to clipboard operation
homeassistant-portainer copied to clipboard

[Feature] Start/Stop/Restart Container possibility ?

Open Raynoxis opened this issue 1 year ago • 15 comments

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

Raynoxis avatar Aug 03 '23 11:08 Raynoxis

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

marcokreeft87 avatar Aug 05 '23 08:08 marcokreeft87

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

tomaae avatar Aug 07 '23 23:08 tomaae

You underestimate the power of the internet haha

marcokreeft87 avatar Aug 08 '23 05:08 marcokreeft87

Thank you for the integration,

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

mhinke avatar Sep 25 '23 07:09 mhinke

Hi,

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

Tscherno avatar Dec 14 '23 19:12 Tscherno

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

Zen3515 avatar Jan 09 '24 16:01 Zen3515

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.

Domi2805 avatar Mar 15 '24 19:03 Domi2805

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

  • packages/portainer/portainer_generic.yaml
  • packages/portainer/cups/portainer_cups_stacks.yaml
  • packages/portainer/cups/portainer_cups_container.yaml

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.

Zen3515 avatar Mar 16 '24 05:03 Zen3515

/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.

Domi2805 avatar Mar 17 '24 10:03 Domi2805

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.

Zen3515 avatar Mar 17 '24 10:03 Zen3515

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!

Domi2805 avatar Mar 17 '24 14:03 Domi2805

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

fufurax avatar Mar 20 '24 16:03 fufurax

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

Zen3515 avatar Mar 20 '24 16:03 Zen3515

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 }}'

fufurax avatar Mar 21 '24 11:03 fufurax

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

alx-xlx avatar Aug 01 '24 06:08 alx-xlx