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

cmd/snap-recovery-chooser: add recovery chooser #8305

Merged
merged 7 commits into from Apr 2, 2020

Conversation

bboozzoo
Copy link
Collaborator

@bboozzoo bboozzoo commented Mar 20, 2020

This is a 2nd version of #8191. The PR implements a recovery chooser that acts as a simple proxy between snapd and the UI tool, currently console-conf. The chooser obtains a list of systems over snapd API endpoint, passes that to the UI process over stdin, then waits for the process to finish and print out the choice to its stdout. The coupling allows us to decouple the UI tool from snapd, where eventually the tool could be part of one of the snaps and run confined.

The PR requires changes from #8298.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Add a recovery chooser host, which talks to snapd and invokes the actual UI
component from snapd internal tools.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
@bboozzoo bboozzoo added the UC20 label Mar 20, 2020
@bboozzoo
Copy link
Collaborator Author

The actual communication method needs more investigation. Looks like urwid library used by console-conf has some opinions about stdin, that are no longer true when we use a pipe there.

@pedronis
Copy link
Collaborator

The actual communication method needs more investigation. Looks like urwid library used by console-conf has some opinions about stdin, that are no longer true when we use a pipe there.

@bboozzoo let me know if you want to chat about that

@bboozzoo
Copy link
Collaborator Author

I was able to fix the issues in console-conf, the the 'blocked' is dropped now.

Copy link
Member

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

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

LGTM, but I would like to see the env var renamed and potentially also a check on the existence of the file marker before we do anything as a sanity check (but maybe I'm wrong about the purpose of the file marker)

}

// for local testing
if os.Getenv("USE_STDOUT") != "" {
Copy link
Member

Choose a reason for hiding this comment

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

could we prefix this env var with SNAPPY_TESTING or something like that to make it clear this is only for tests and shouldn't be relied on by anybody else?

})

c.Assert(s.markerFile, testutil.FileAbsent)

Copy link
Member

Choose a reason for hiding this comment

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

unnecessary whitespace ?

Suggested change


func chooser(cli *client.Client) error {
// consume the trigger file
defer cleanupTriggerMarker()
Copy link
Member

Choose a reason for hiding this comment

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

should we also actually check that there is a marker file before we run (and then delete it if there is)?

I think it's unlikely this binary will ever be used except by something which sees the trigger file and then triggers this to run, but still perhaps it's a good idea?

…rtup

Forward the response from the UI back to snapd.

Also look at SNAPPY_TESTING instead of USE_STDOUT.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
@@ -119,6 +137,15 @@ func cleanupTriggerMarker() error {
}

func chooser(cli *client.Client) error {
snappyTesting := os.Getenv("SNAPPY_TESTING") != ""
Copy link
Member

Choose a reason for hiding this comment

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

won't this change the behavior during spread tests generally? Or perhaps this binary will only ever be used in spread in an artificial way?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ah, didn't notice setting this top level in spread.yaml 😞

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Copy link
Member

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

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

Still LGTM with the actual call to the snapd API at the end

Copy link
Collaborator

@zyga zyga left a comment

Choose a reason for hiding this comment

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

Looks really nice.

I left a few comments about packaging and some questions here and there.

cmd/snap-recovery-chooser/main.go Show resolved Hide resolved
func outputForUI(out io.Writer, sys *ChooserSystems) error {
enc := json.NewEncoder(out)
if err := enc.Encode(sys); err != nil {
return fmt.Errorf("cannot serialize chooser options: %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency between the message and the type.

Suggested change
return fmt.Errorf("cannot serialize chooser options: %v", err)
return fmt.Errorf("cannot serialize chooser systems: %v", err)

}

func chooser(cli *client.Client) error {
snappyTesting := os.Getenv("SNAPPY_TESTING_USE_STDOUT") != ""
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have those "getenv bool" helpers. This looks like a place to use one.

Copy link
Collaborator

Choose a reason for hiding this comment

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

the SNAPPY_ prefix is historical, we use SNAPD_ these days, please let's not use it for new things

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll go with SNAPD_TESTING_USE_STDOUT.

Copy link
Contributor

Choose a reason for hiding this comment

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

You could use osutil.GetenvBool() here which would make this a bit more natural, the current code will behave unexpectedly when using "SNAPPY_TESTING_USE_STDOUT=false" (but I guess zyga said this already).

Copy link
Contributor

Choose a reason for hiding this comment

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

We could do something like https://paste.ubuntu.com/p/sXqWJkT7wp/ and check the outputForUI this way (or keeping in a separate test with something like https://paste.ubuntu.com/p/s86HQY8zfn/)

return fmt.Errorf("UI process failed: %v", err)
}

logger.Noticef("got response: %+v", response)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What does %+v do?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

%v	the value in a default format
	when printing structs, the plus flag (%+v) adds field names

})
c.Assert(err, IsNil)
default:
c.Fatalf("expected to get 1 requests, now on %d", n+1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick, the number here is zero-based, which might be surprising if the test ever fails and someone has to debug it.

Copy link
Collaborator Author

@bboozzoo bboozzoo Apr 1, 2020

Choose a reason for hiding this comment

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

It's a pattern we use throughout the client/snap command tests. Still, the message should say at most 2 requests.., so fixed that.

}

func (s *mockedClientCmdSuite) TestMainChooserStdout(c *C) {
os.Setenv("SNAPPY_TESTING_USE_STDOUT", "1")
Copy link
Collaborator

Choose a reason for hiding this comment

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

This makes me wonder, should the side that reads this be using snapdenv?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The flag is only used in the snap-recovery-chooser binary.

Copy link
Collaborator

Choose a reason for hiding this comment

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

if it's very specific to testing this code I would say no. For the moment the main candidates for snapdenv are things used by more than one package, or well advertised to users

@@ -9,6 +9,7 @@ usr/bin/snapd /usr/lib/snapd/
usr/bin/snap-seccomp /usr/lib/snapd/
usr/bin/snap-bootstrap /usr/lib/snapd/
usr/bin/snap-preseed /usr/lib/snapd/
usr/bin/snap-recovery-chooser /usr/lib/snapd/
Copy link
Collaborator

Choose a reason for hiding this comment

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

The DM in me would say, please write a manual page.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No user is expected to ever run that themselves.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Then it should be in libexecdir

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, wait, it is. I take that back :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

${libexecdir}/snapd is /usr/lib/snapd on Ubuntu, isn't it?

usr/bin/snap-bootstrap
usr/bin/snap-recovery-chooser
Copy link
Collaborator

@zyga zyga Apr 1, 2020

Choose a reason for hiding this comment

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

Do you need to handle this in packaging/snapd.mk, namely to remove it like so:

ifeq ($(with_core_bits),0)
# Remove core 20 recovery chooser
install::
    rm -f $(DESTDIR)$(bindir)/snap-recovery-chooser
endif

Copy link
Collaborator Author

@bboozzoo bboozzoo Apr 1, 2020

Choose a reason for hiding this comment

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

We just don't build it there as it has no use outside of Ubuntu package.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, indeed. I was under the impression we build all go binaries. This is fine though I would prefer to have it for completeness, with the hope that this makefile can be used in all packaging at some point.

@bboozzoo
Copy link
Collaborator Author

bboozzoo commented Apr 2, 2020

The PR in subiquity canonical/subiquity#655 has landed.

@mvo5 mvo5 added this to the 2.45 milestone Apr 2, 2020
@bboozzoo
Copy link
Collaborator Author

bboozzoo commented Apr 2, 2020

And additional fixes in canonical/subiquity#680 have landed too. We should probably merge this PR and do any tweaks in follow ups.

Copy link
Contributor

@mvo5 mvo5 left a comment

Choose a reason for hiding this comment

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

This looks fine, I have some nitpicks inside but all followup material

}
// TODO:UC20 update once upstream console-conf has the right command
// line switches
return exec.Command(tool, "--recovery-chooser-mode"), nil
Copy link
Contributor

Choose a reason for hiding this comment

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

The upstream console-conf changes have landed, so is this still a valid todo?

// reuse stderr
cmd.Stderr = os.Stderr
// the chooser may be invoked via console-conf service which uses
// KillMethod=process, so make sure the UI process dies when we die
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! Also thanks for the comment.

}

func cleanupTriggerMarker() error {
err := os.Remove(defaultMarkerFile)
Copy link
Contributor

Choose a reason for hiding this comment

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

(nitpick^2) I think slightly more go-ish would be:

if err := os.Remove(defaultMarkerFile); err != nil && !os.IsNotExit(err) { 
    return err
} 
return nil 

but I already feel bad writing this comment as it's sooooooo much a nitpick

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This and some other tweaks are done in #8415

}

func chooser(cli *client.Client) error {
snappyTesting := os.Getenv("SNAPPY_TESTING_USE_STDOUT") != ""
Copy link
Contributor

Choose a reason for hiding this comment

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

You could use osutil.GetenvBool() here which would make this a bit more natural, the current code will behave unexpectedly when using "SNAPPY_TESTING_USE_STDOUT=false" (but I guess zyga said this already).

}

// for local testing
if snappyTesting {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not at the point yet where I see how this is used but it makes me wonder if for testing we could have something like a "testingUI" that capture stdin and gives canned replies

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

When testing locally it's sometimes useful to do:

$ USE_STDOUT=1 snap-recovery-chooser | console-conf --recovery-chooser-mode
# or
$ USE_STDOUT=1 snap-recovery-chooser > canned-input
$ console-conf --recovery-chooser-mode < canned-input

@mvo5 mvo5 merged commit c998d9a into snapcore:master Apr 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants