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: Run 'crc daemon' as task for 'crc setup' #3088
Conversation
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.
There is a known issue with windows powershell when you start a task in background using
powershell.exe
then for a second the windows pops up and disappear, PowerShell/PowerShell#3028
Looks like this can be worked around though?
<WaitTimeout>PT1H</WaitTimeout> | ||
<StopOnIdleEnd>true</StopOnIdleEnd> | ||
<RestartOnIdle>false</RestartOnIdle> | ||
</IdleSettings> |
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.
Is this stopping after being idle for a while? How is "idle" defined?
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.
@cfergeau no it is stopping it intantly. This template is exported from a task and didn't modified.
@@ -0,0 +1,44 @@ | |||
package preflight | |||
|
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.
Not sure a separate file is needed when you already add preflight_daemon_service_check_windows.go
A task_win.go
file would make sense if most of the preflight check/fix code was moved to a higher level API to handle Windows tasks. The current separation does not soundu so useful.
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.
I don't mind it to move this part to task_windows.go
// prepare the task script | ||
binPath, err := goos.Executable() | ||
if err != nil { | ||
return fmt.Errorf("unable to find the current executables location: %v", err) |
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.
executable
(without the trailing s
)
if err != nil { | ||
return fmt.Errorf("unable to find the current executables location: %v", err) | ||
} | ||
binPathWithArgs := fmt.Sprintf("%s daemon", strings.TrimSpace(binPath)) |
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.
Why TrimSpace
?
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.
In case output have spaces in between.
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.
But are you getting spaces when you test it? Or are there concrete cases when you know for sure there will be spaces that we need to remove? This is what is not clear to me :)
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.
Removed, because binPath
string is what we are creating so should be done it properly there.
logging.Debugf("%s task is not running: %v : %s", constants.DaemonTaskName, err, stderr) | ||
return err | ||
} | ||
if strings.TrimSpace(stdout) != "Running" { |
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.
Is this working as expected on localized Windows versions?
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.
@cfergeau That I didn't check and love to know if that works with localized version.
var daemonServiceChecks = []Check{ | ||
{ | ||
configKeySuffix: "check-daemon-task-install", | ||
checkDescription: "Check if daemon task is installed", |
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.
I think the other preflights are using Checking
...Installing...
, ...
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.
Ah yes, I will improve that.
The workaround use |
Has it already been tried to have our own small helper non-console binary which would just run the appropriate powershell comnad? or would it also be detected as a virus? |
c4f1dfe
to
44b868a
Compare
@cfergeau own small helper you mean create a small go binary which run |
I think it's |
It is not the |
36cfc03
to
6e65f8f
Compare
Ah, so each time the daemon is started, a console window flashes on the screen. Have you tried what is suggested in https://stackoverflow.com/questions/23250505/how-do-i-create-an-executable-from-golang-that-doesnt-open-a-console-window-whe instead of using powershell.exe? |
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.
Approved
@jsliacan have you been able to test this in an update scenario?
Yes, if I use this during build of package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 120; i++ {
fmt.Println("This is for testing purpose")
time.Sleep(time.Second)
}
} PS C:\Users\prkumar\work\github\practise\test> go build -ldflags -H=windowsgui -o wintest.exe main.go
PS C:\Users\prkumar\work\github\practise\test> .\wintest.exe
PS C:\Users\prkumar\work\github\practise\test> <-- Process directly goes to background without any print on stdout -->
PS C:\Users\prkumar\work\github\practise\test> Get-Process wintest
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
82 8 12472 5232 0.03 54140 3 wintest |
|
Yes, I suspected we do not want to build
I'm not sure what you mean with these 2 sentences?
Sure, but this begs a few questions:
|
@praveenkumar @anjannath should we modify the tray to check for this scheduled task and task accordingly if not running? |
var buf bytes.Buffer | ||
if err := xml.EscapeText(&buf, []byte(binPathWithArgs)); err != nil { | ||
return err | ||
} |
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 belongs in genDaemonTaskInstallTemplate
, not here. If you do it here, this means all callers of genDaemonTaskInstallTemplate
have to be aware of it. This also kind of hardcodes in fixDaemonTaskInstalled
that genDaemonTaskInstallTemplate
will be doing fmt.Sprintf(xml, ...)
. fixDaemonTaskInstalled
has no need to know that, this just muddles unrelated abstraction layers
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.
@cfergeau you want something like following?
package main
import (
"bytes"
"encoding/xml"
"fmt"
"log"
)
func genDaemonTaskInstallTemplate(crcVersion, daemonServiceName string) (string, error) {
var buf bytes.Buffer
fmt.Fprintf(&buf, `<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.3" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Description>Run crc daemon as a task</Description>
<Version>%s</Version>
</RegistrationInfo>
<Settings>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<Hidden>true</Hidden>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<IdleSettings>
<Duration>PT10M</Duration>
<WaitTimeout>PT1H</WaitTimeout>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
</Settings>
<Triggers />
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-WindowStyle Hidden -Command `, crcVersion)
err := xml.EscapeText(&buf, []byte(daemonServiceName))
fmt.Fprintf(&buf, `</Arguments>
</Exec>
</Actions>
</Task>`)
return buf.String(), err
}
func main() {
s, err := genDaemonTaskInstallTemplate("2.0.1", `C:\windows\crc.exe`)
if err != nil {
log.Fatal(err)
}
fmt.Println(s)
}
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.
Not very easy to read with the XML embedded in the function, but I had in mind something like this:
func genDaemonTaskInstallTemplate(crcVersion, daemonServiceName string) (string, error) {
var escapedName bytes.Buffer
if err := xml.EscapeText(&escapedName, []byte(daemonServiceName)); err != nil {
return "", err
}
return fmt.Sprintf(daemonTaskTemplate,
crcVersion,
escapedName.String(),
), nil
}
@cfergeau I think it should be OK to take this PR as of now with flashing window.
@cfergeau No, because this flashing window is not something user even notice and if even they do we have it part of the known issue. we only improve it, revert only take place if there is an alternative to task manager which can run |
Err, sorry, but I'd definitely notice, and find this ugly and unpolished from whatever application did this. Let's not make blanket statements regarding what users would or would not notice. |
@cfergeau Wrong wording in the sentense. |
/hold |
This PR is uses windows powershell to create `crc daemon` as task and start it on demand for the current user. This doesn't need any elevated privillages to run `crc daemon` for user context. It try to perform following tasks - Check if there is already crcDaemon task + If present does it the latest one using version info - Install the task using predefined xml definition - Start the task which run the `crc daemon` in background. There is a known issue with windows powershell when you start a task in background using `powershell.exe` then for a second the windows pops up and disappear, PowerShell/PowerShell#3028 have more details around it but as of now this is only the way for interactive user context otherwise the task will need the admin privillages which we want to avoid.
Admin helper service is created and started when installer is used. Some of the issue we are getting is user directly try to use crc from command line and see if the openshift routes are mapped in hosts file. This PR is help to detect if the service is running and it doesn't need any privilage permission but it doesn't create or start this service because that need administrator privilages.
This PR will remove the crc daemon schedule task during the uninstallation, as of now even with this PR when the task is running and user try to uninstall then uninstaller warn user that `crc` binary in used and user have option to forceful stop it and carry on or go to task manager and kill it manually.
This PR remove preflight checks for daemon command because daemon can run independent of a crc setup. the actual check happens when you perform a `crc start`. Since those tests run as part of crc daemon which takes around 5-6 sec so initial api response become block for 5-6 sec.
@praveenkumar: The following tests failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/unhold |
Without this PR following scenario happen - User installed the crc first time and do the setup - As part of the setup crc daemon is started by task schedular - User reboot - Tray autostart with reboot but `crc setup --check-only` fails because daemon task is not running. With this PR, check for daemon task running should first validate if an existing process of `crc daemon` is running and the version it get from the api should be same as the binary then task running check succeed. So this PR will makes `crc setup --check-only` work again with tray autostart.
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: anjannath, gbraad, praveenkumar The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Tested the end to end flow (both from cli and tray) and its working as expected |
This PR is uses windows powershell to create
crc daemon
as taskand start it on demand for the current user. This doesn't need any
elevated privillages to run
crc daemon
for user context. It try toperform following tasks
crc daemon
in background.There is a known issue with windows powershell when you start a task
in background using
powershell.exe
then for a second the windows popsup and disappear, PowerShell/PowerShell#3028
have more details around it but as of now this is only the way for
interactive user context otherwise the task will need the admin
privillages which we want to avoid.