-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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] Implement executor on Windows #3517
[Windows] Implement executor on Windows #3517
Conversation
aaed23e
to
43c1ff4
Compare
util/windows/utils_windows.go
Outdated
procInfo := executor.ProcessInfo{ | ||
Meta: executor.Meta{ | ||
Args: []string{"get-user-info", userName}, | ||
User: "ContainerAdministrator", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this run as ContainerUser
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returns Access Denied
if I remember correctly. Will double check.
Don't grow this into a very large single commit. We'll be happy to take windows-modified updates so single packages or groups of functions without the full thing being ready. Eg. #3544 is a nice example. |
Indeed! I wanted to first figure out all the needed bits to get Once that is done I plan to circle back and split things up, respond to reviews and get everything in a state that is easy to review and merge. |
4c6eaad
to
85cd781
Compare
This change splits the containerdexecutor.Run() function into smaller pieces and enables it to run on Windows. Signed-off-by: Gabriel Adrian Samfira <[email protected]>
85cd781
to
b6b322b
Compare
I rebased this PR and it's ready for review. Most of the changes are code shuffle in smaller functions and the addition of the Windows specific bits. PTAL if you have the time. |
CC @crazy-max @jedevc if you have some time to review, I would appreciate it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will wcow be containerd-worker only?
return releaseAll, resolvConf, hostsFile, nil | ||
} | ||
|
||
func (w *containerdExecutor) getTaskOpts(ctx context.Context, details *jobDetails) (containerd.NewTaskOpts, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can just be a method on containerState
(jobDetails), same for cwd
. Not sure if makes sense for others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added getTaskOpts
to containerState
.
}, nil | ||
} | ||
|
||
func (w *containerdExecutor) prepareExecutionEnv(ctx context.Context, rootMount executor.Mount, mounts []executor.Mount, meta executor.Meta, details *jobDetails) (func(), string, string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't ideal that this is a mix of 2 things: preparing /etc
files and setting up properties of details
(otherwise I would call this prepareEtcPaths
. If it is already a mix, then why is CWD
different? If you don't have better ideas then rename the cwd to prepareCWD
so it is consitent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't ideal that this is a mix of 2 things: preparing /etc files and setting up properties of details
I can add the /etc
files as fields in details and keep things consistent. This way each platform can pick and choose what they need. Would that be better?
(otherwise I would call this prepareEtcPaths.
It also records the rootfsPath
on Linux and rootMounts []mount.Mount
on Windows. These are used later to ensure the CWD exists and so they can also be used later in Exec()
, fixing the exiting TODO
.
. If it is already a mix, then why is
CWD
different?
The CWD
is a bit different because on Windows we're pretty much forced to boot up a container to get the SID (Security Identifier) of the owner of the CWD
.
There is that whole song and dance in the windows
version that calls into windows.ResolveUsernameToSID()
, which passes in the executor so it can resolve the user SID without reimplementing the executor elsewhere. That's why it's attached to the executor. I can attach it to containerState{}
and pass in the executor (and any other parameters it needs) as an arg.
How would you prefer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will wcow be containerd-worker only?
At this point, yes.
}, nil | ||
} | ||
|
||
func (w *containerdExecutor) prepareExecutionEnv(ctx context.Context, rootMount executor.Mount, mounts []executor.Mount, meta executor.Meta, details *jobDetails) (func(), string, string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't ideal that this is a mix of 2 things: preparing /etc files and setting up properties of details
I can add the /etc
files as fields in details and keep things consistent. This way each platform can pick and choose what they need. Would that be better?
(otherwise I would call this prepareEtcPaths.
It also records the rootfsPath
on Linux and rootMounts []mount.Mount
on Windows. These are used later to ensure the CWD exists and so they can also be used later in Exec()
, fixing the exiting TODO
.
. If it is already a mix, then why is
CWD
different?
The CWD
is a bit different because on Windows we're pretty much forced to boot up a container to get the SID (Security Identifier) of the owner of the CWD
.
There is that whole song and dance in the windows
version that calls into windows.ResolveUsernameToSID()
, which passes in the executor so it can resolve the user SID without reimplementing the executor elsewhere. That's why it's attached to the executor. I can attach it to containerState{}
and pass in the executor (and any other parameters it needs) as an arg.
How would you prefer?
return releaseAll, resolvConf, hostsFile, nil | ||
} | ||
|
||
func (w *containerdExecutor) getTaskOpts(ctx context.Context, details *jobDetails) (containerd.NewTaskOpts, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added getTaskOpts
to containerState
.
Signed-off-by: Gabriel Adrian Samfira <[email protected]>
ce9e636
to
cc5657c
Compare
Failure seems to be unrelated to the changes. May be worth triggering that job again. |
(I apologize for the large wall of text bellow)
This change enables the
containerd
executor to run on Windows. It builds on the great work started by @TBBle .Most of the changes are just a reshuffle of existing code in smaller platform specific functions, with Windows specific changes made.
Some things happening in this PR
localmounter
is only needed when ensuring the CWD. In all other cases, we need to pass the layers in as they are andcontainerd
/hcsshim
will handle the proper mounting. We cannot pass in abind
mount as a root filesystem.Fetching the SID of the user
Linux uniquely identifies users on a system, using their UID. This information is stored in
/etc/passwd
and can easily be parsed by simply mounting the root filesystem and reading that file.On Windows, there is an equivalent to both
/etc/passwd
and/etc/group
in the form of a registry hive calledSAM
. This file can be found on all Windows systems inC:\Windows\System32\config\SAM
.This hive holds all user information on a particular system, including the SID of the user we care about. The bad news is that the data structures in this hive are completely undocumented and there is no API we can call to load the security info inside an offline SAM hive. We can load it as a registry hive, but parsing the data structures it holds is not documented. It's not impossible to do, but in the absence of an officially supported API to do this for us, we risk that sometime in the future our parser will break.
An attempt to parse the hive was made here: #3248
The alternative is to execute a utility in the context of a container to fetch the SID. This means that we need to run a binary that needs to exist in the container, which will use Windows APIs to fetch the SID of the user. To do this, we defined a small utility as a
reexec
function in buildkitd, which allows us to mountos.Executable()
inC:\Windows\System32\get-user-info.exe
and get the SID.There are shortcuts to get the SID of well known accounts/groups, including the default
ContainerAdministrator
andContainerUser
. As long as there is no explicitUSER
stanza that defines a manually created user (viaRUN net user testuser /ADD /ACTIVE:yes
), this code path will be bypassed.At this stage, this is just a draft, as it needs a number of other changes to land in various projects. A (hopefully) complete list bellow. Will amend the list if more are needed:
Partially addresses: microsoft/Windows-Containers#34
Signed-off-by: Gabriel Adrian Samfira [email protected]