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

Windows Container support #96

Closed
wants to merge 8 commits into from
Closed

Windows Container support #96

wants to merge 8 commits into from

Conversation

tmeckel
Copy link

@tmeckel tmeckel commented Mar 1, 2021

SUMMARY

This PR contains changes to docker.py to support Windows Containers.

ISSUE TYPE
  • Feature Pull Request

Copy link
Collaborator

@felixfontein felixfontein left a comment

Choose a reason for hiding this comment

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

Thanks for this contribution!

I can't review this fully since I don't have or use Windows; I'll mainly make sure that the code looks good and that it won't break the non-Windows side :-)

Two things:

  1. This needs a changelog fragment;
  2. Please remove the display.debug statements that dump stdout/stderr. This could accidentally dump secrets into logs where they do not belong.

* Added changelog fragment
@tmeckel
Copy link
Author

tmeckel commented Mar 2, 2021

@felixfontein Thank for the quick reply on my PR!
I changed the code and added a changelog fragment.

changelogs/fragments/96-windows-support.yaml Outdated Show resolved Hide resolved
plugins/connection/docker.py Outdated Show resolved Hide resolved
plugins/connection/docker.py Outdated Show resolved Hide resolved
tmeckel and others added 2 commits March 2, 2021 19:45
@felixfontein felixfontein requested a review from jborean93 March 2, 2021 19:30
Copy link
Collaborator

@felixfontein felixfontein left a comment

Choose a reason for hiding this comment

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

The non-Windows part of this PR looks good (i.e. it should not break anything ;) ).

@tmeckel
Copy link
Author

tmeckel commented Mar 2, 2021

@felixfontein Why are the RHEL 8.2 tasks in the CI pipeline are failing. Is this relevant to my PR?

changelogs/fragments/96-windows-support.yaml Outdated Show resolved Hide resolved
plugins/connection/docker.py Outdated Show resolved Hide resolved
Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>
@felixfontein
Copy link
Collaborator

@tmeckel the RHEL issues are unrelated to this PR, there seems to be something wrong with the setup of the VMs. I've pinged someone to investigate.

@felixfontein
Copy link
Collaborator

The RHEL will be fixed by #97.

@felixfontein
Copy link
Collaborator

Tests should now pass. Let's see :)

@felixfontein
Copy link
Collaborator

recheck

@felixfontein
Copy link
Collaborator

@briantist @jborean93 I plan to create a new release of community.docker on Monday or Tuesday next week (so it can get included in Ansible 3.1.0). If you don't manage to review the PR until then, I can also create another release once this is merged, so no pressure ;)

@briantist
Copy link
Contributor

I plan to create a new release of community.docker on Monday or Tuesday next week (so it can get included in Ansible 3.1.0). If you don't manage to review the PR until then, I can also create another release once this is merged, so no pressure ;)

I'm not sure I'll be able to actually run this to try it out unfortunately, certainly not before your next release. I'll see if I get a chance to try it out at some point

Copy link

@jborean93 jborean93 left a comment

Choose a reason for hiding this comment

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

Some nice edge case stuff in the review but what you have here is pretty good.

I will highly recommend that tests be added as soon as possible, there are a few private functions and edge cases with Windows that are hard to keep track off without tests actually testing those scenarios.

plugins/connection/docker.py Show resolved Hide resolved
local_cmd = self._build_exec_cmd([self._play_context.executable, '-c', cmd])
if getattr(self._shell, "_IS_WINDOWS", False):
sudoable = False
local_cmd = self._build_exec_cmd(["cmd", "/c", cmd])

Choose a reason for hiding this comment

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

I might be wrong but I believe using cmd /c here will mean any raw task with the connection plugin will be using cmd as the shell rather than PowerShell. You may want to change this based on whether the ansible_shell_type is either cmd or powershell to allow a user to change this as they desire.

Copy link
Author

@tmeckel tmeckel May 5, 2021

Choose a reason for hiding this comment

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

@jborean93 yes this is true. Bit when I change the code as follows I receive a file not found. So the interpreter (Powershell) cannot be found. So I suspect I didn't grasp what you meant by saying I should utilize the ansible_shell_type. Any guidance?

image

Choose a reason for hiding this comment

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

Do you know what the default shell is for a Windows container, i.e. what runs when you do docker exec .... Is it cmd or is it powershell.exe, or maybe no shell at all?

Basically right now if someone was to do the following

- raw: echo "hi"

Is that going to be running under cmd or powershell? With the current changes here that will be running as cmd which might not be ideal if someone has set ansible_shell_type=powershell. Maybe the desire is to have raw with this connection plugin independent to the shell plugin used, if that's the case then the PR as it is makes sense. If you wish for this to be dependent on the shell plugin then you will have to hardcode cmd.exe /c when using the cmd shell and powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command for the powershell shell.

This might be something that @felixfontein may want to comment on.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think I can say something here. I've never used Docker with Windows containers, so I have zero experience what these contain.

Choose a reason for hiding this comment

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

I mostly mean more in general, do you expect that raw should match the ansible_shell_type (powershell or cmd) or should it just be the same thing on the connection plugin?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Matching ansible_shell_type would be nice I guess, though I'm not even sure whether Linux containers fully support that (I've never really looked at shell plugins). I also have no idea how complicated it would be to 'properly' implement this.

plugins/connection/docker.py Show resolved Hide resolved
@@ -308,11 +330,32 @@ def put_file(self, in_path, out_path):
count = ' count=0'
else:
count = ''
args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)])
if getattr(self._shell, "_IS_WINDOWS", False):
cmd = '''& { $strm = [Console]::OpenStandardInput(1024)

Choose a reason for hiding this comment

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

If you use _encode_script as per below you can skip the & { ... } entirely and just run the command as is.

Copy link
Author

Choose a reason for hiding this comment

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

@jborean93 changed the code as advised, but I receive an invalid payload

image

image

Choose a reason for hiding this comment

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

I'm not sure what is happening here, the error you've shared is something that is thrown by the bootstrap_wrapper.ps1 which is used when executing a module. The code you have here is for copying a file to the docker container and shouldn't be calling the bootstrap_wrapper code.

if getattr(self._shell, "_IS_WINDOWS", False):
cmd = '''& { $strm = [Console]::OpenStandardInput(1024)
$data = [System.Array]::CreateInstance([byte],1024)
$fstrm = [IO.File]::OpenWrite(%s)

Choose a reason for hiding this comment

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

You still need to have more logic to handle here. Right now at a quote glance I could have a path like:

’+ (&[ScriptBlock]::Create([[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("my code to inject")) +’

Note the use of unicode smart quotes

PowerShell (un)helpfully treats a bunch of smart quotes as the same as single quotes so even if you ran shlex_quote on your path it won't escape what is needed. As soon as you can escape outside of a quote you can embed whatever command you want to run here.

There are 2 choices I can see you moving to:

  • Use a the same (or similar regex) to the ansible.windows quote filter for powershell to escape the smart quotes and give you a literal value
  • Base64 encode the path and decode that in your script - base64 means you no longer have to deal with quotes or unicode characters
cmd = '''
...
$outPath = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('%s'))
...
''' % (to_text(base64.b64encode(to_bytes(out_path, encoding='utf-8'))))

Both options remove the need for `shlex_quote` but I still recommend you normalize the path as you have done today.

@felixfontein
Copy link
Collaborator

I will highly recommend that tests be added as soon as possible, there are a few private functions and edge cases with Windows that are hard to keep track off without tests actually testing those scenarios.

There's one big problem with Windows container tests: someone has to create and maintain them. Since Windows containers cannot run on Linux, this requires the tests to run on Windows. Our CI (AZP) theoretically does support that, but we've never run tests on Windows for any of the docker plugins and modules yet. So this is far from simple to set up.

@jborean93
Copy link

Totally understand that problem, at a quick glance you could do what we did for testing SSH against Windows hosts. Still spin up an AWS EC2 instance for Windows Server 2019 and install the Containers feature and a running container. I'm not sure if it's possible to even expose the Docker port over the internet like that so that might be a no go. Ultimately it's up to you as the maintainers what you would like to have. I just know this is going to be painful to support going forwards without some kind of tests around it.

@jimbo8098
Copy link

jimbo8098 commented Mar 17, 2021

If this were to be accepted, I have a CI pipeline for my organisation which would make use of these utilities for docker swarm creation and more. We use WinRM and Windows Server 2019 predominantly but resources to work with others since idempotent IasC is in it's infancy here.

I was actually on my way to find out the views of me PRing the community.docker.docker_swarm module to support Windows!

Therefore, watching this and stand ready to assist.

@felixfontein
Copy link
Collaborator

@jimbo8098 I'm happy to merge this (once all review comments are addressed) also without Windows tests. We (or in particularly I :-) ) don't mind Windows-specific PRs - as long as they don't break other platforms.

It would be great to have Windows tests in this repository as well; as long as we don't have them, Windows support in the modules is "use on your own risk, we try not to break it, but we won't notice in case we do". If your CI pipeline uses say the main branch of this collection, you would notice early if something breaks and you could create an issue (or even a PR to fix it), so that releases should usually work for Windows :)

@jimbo8098
Copy link

Just to add to my previous point, Our infrastructure is Windows Server 2019 hardware, not containers. I suspect the two should be the same in a CI environment if you are just building towards testing infra for this though some mechanisms of course might be a bit different. Will look to PR on docker_swarm for the moment but I'll be watching this.

@felixfontein
Copy link
Collaborator

@tmeckel do you have time to incorporate the latest review comments? It would be great if we could get this merged.

@felixfontein felixfontein mentioned this pull request Apr 11, 2021
@tmeckel
Copy link
Author

tmeckel commented Apr 17, 2021

@felixfontein sorry for the delay. Found some time to work on the comments of @jborean93

@felixfontein
Copy link
Collaborator

@tmeckel ping

@tmeckel
Copy link
Author

tmeckel commented May 5, 2021

@felixfontein added comments. Awaiting answers from @jborean93

@felixfontein felixfontein added the docker-plain plain Docker (no swarm, no compose, no stack) label May 21, 2021
@tmeckel tmeckel closed this Nov 3, 2023
@tmeckel tmeckel deleted the windows-support branch November 3, 2023 07:35
Copy link

github-actions bot commented Nov 3, 2023

Docs Build 📝

This PR is closed and any previously published docsite has been unpublished.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docker-plain plain Docker (no swarm, no compose, no stack)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants