feat(login): Persist non-default --server to the config file - #363
feat(login): Persist non-default --server to the config file#363lluiscampos wants to merge 1 commit into
Conversation
|
Hello I am using eu.hosted.io for my PoC and this feature helps me greatly to not end up having annoying 401 because I forgot to specify the server url. From a user point of view, if I do "mender-cli login ..." and the valid token is saved in disk, it would be nice that the info about where the token is valid (server url) is also saved in disk. |
|
Hello @lluiscampos and what a nice surprise to see this! |
After a successful login with an explicit --server pointing to something different than hosted.mender.io, create or update .mender-clirc for further commands to use. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Lluis Miquel Martinez Campos <lluiscampos@proton.me>
mzedel
left a comment
There was a problem hiding this comment.
Thanks you! I'll leave the final verdict to someone else, but for CI to pass we would require you to: Make sure that the Author of the commit matches the one in Signed-off-by 😉
0c055f0 to
5b9e0b2
Compare
|
Heyho @mzedel as representative of the server team 😉 I fixed the linting issue and the signed-off-by 👍
Do you mean an extension for mender-artifact tool to do server operations like upload? I don't understand your sentence. So far |
Exactly that! For me the artifact handling is very much aligned with e.g. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
I see. It is true that from a user point of view it makes sense (my same CI job will do mender-artifact write + mender-artifact upload) but I know by a fact from your internal point of view this is adding even more dependencies to an already bloated tool that is used from microservices (hence security sensitive). Not to mention yocto compatibility with its old golang versions around... It is not my decision to make 😉 |
merlin-northern
left a comment
There was a problem hiding this comment.
Thank you very much for continuing interest in the Mender Project, and for using it. Thank you also for the contribution. The proper way of doing what you need is:
diff --git a/cmd/root.go b/cmd/root.go
index 8f5e0f3..9e30221 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -39,6 +39,8 @@ const (
)
func init() {
+ viper.SetEnvPrefix("MENDER_CLI")
+ viper.BindEnv(argRootServer)
viper.SetConfigName(".mender-clirc")
viper.SetConfigType("json")
viper.AddConfigPath("/etc/mender-cli/")and persisting the MENDER_CLI_SERVER_URL in your shell rc/env managing system you use.
If you are still willing to provide that contribution I am willing to listen to it. Note that the AutomaticEnv is something to consider, as well as documenting the new behaviour (consider what if someone had had MENDER_CLI_* vars declared, and now they start being parsed by the new version of mender-cli -- there are also ways around it). Please also do not leave the "MENDER_CLI" as a magic string.
| if err != nil { | ||
| return ".mender-clirc" | ||
| } | ||
|
|
||
| return filepath.Join(home, ".mender-clirc") |
There was a problem hiding this comment.
magic string -- now in 3 places in total in the code, not counting the tests (another 8)
| // if it does not exist. If the file already contains a "server" key, it is | ||
| // left untouched and false is returned. Otherwise the key is written and true | ||
| // is returned. | ||
| func persistServerToConfig(path string, server string) (bool, error) { |
There was a problem hiding this comment.
this call overwrites a config file. what if there is another mender-cli running? what if my wife is editing my config file at the same time with ed? what if I had my super secret server url there, which is now lost forever, do we have it saved somewhere? what if i had a config file in some other location? /etc ~/ or .? btw the modern distros use ~/.confg. what if I am very particular about what is created and where? now mender-cli created directories, files, and all that? have I been warned? where is it documented?
There was a problem hiding this comment.
this call overwrites a config file. what if there is another mender-cli running? what if my wife is editing my config file at the same time with
ed? what if I had my super secret server url there, which is now lost forever, do we have it saved somewhere? what if i had a config file in some other location?/etc~/or.?
Are you concerned about the race condition of two instances writing this file (which fair enough I ignored it for the sake of simplicity) or are you concerned about the fallback of config files?
For the later (which is the only that I think we should be concerned about) mender-cli already looks for three different places: /etc, working dir, and home. The logic in this PR tries to find any of these, if existing, and adds the server url. if none exists it defaults to the home vesion.
btw the modern distros use
~/.confg. what if I am very particular about what is created and where?
Please be specific: what are you asking for with this comment?
- The
.configis already mising from the tool and sounds like a huge scope creep. - "If I am very particular..." I guess that means that you want an option to decide on where to create the config file? But then with even less effort you can crate the file yourself if you are so particular
now mender-cli created directories, files, and all that? have I been warned?
mender-cli already creates directories and files to save the auth token, no warning
where is it documented?
Can you please guide me on where to document it? --help?
lluiscampos
left a comment
There was a problem hiding this comment.
Thank you very much for continuing interest in the Mender Project, and for using it. Thank you also for the contribution.
Thank you very much for continuing developing such a great product. Thank you also for reviewing my contribution.
The proper way of doing what you need is:
diff --git a/cmd/root.go b/cmd/root.go index 8f5e0f3..9e30221 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -39,6 +39,8 @@ const ( ) func init() { + viper.SetEnvPrefix("MENDER_CLI") + viper.BindEnv(argRootServer) viper.SetConfigName(".mender-clirc") viper.SetConfigType("json") viper.AddConfigPath("/etc/mender-cli/")and persisting the
MENDER_CLI_SERVER_URLin your shell rc/env managing system you use.If you are still willing to provide that contribution I am willing to listen to it. Note that the
AutomaticEnvis something to consider, as well as documenting the new behaviour (consider what if someone had had MENDER_CLI_* vars declared, and now they start being parsed by the new version of mender-cli -- there are also ways around it). Please also do not leave the"MENDER_CLI"as a magic string.
I don't understand... do you mean to apply this diff (viper is a a box of surprises for me!) instead of the rest of the PR? Please be explicit.
| // if it does not exist. If the file already contains a "server" key, it is | ||
| // left untouched and false is returned. Otherwise the key is written and true | ||
| // is returned. | ||
| func persistServerToConfig(path string, server string) (bool, error) { |
There was a problem hiding this comment.
this call overwrites a config file. what if there is another mender-cli running? what if my wife is editing my config file at the same time with
ed? what if I had my super secret server url there, which is now lost forever, do we have it saved somewhere? what if i had a config file in some other location?/etc~/or.?
Are you concerned about the race condition of two instances writing this file (which fair enough I ignored it for the sake of simplicity) or are you concerned about the fallback of config files?
For the later (which is the only that I think we should be concerned about) mender-cli already looks for three different places: /etc, working dir, and home. The logic in this PR tries to find any of these, if existing, and adds the server url. if none exists it defaults to the home vesion.
btw the modern distros use
~/.confg. what if I am very particular about what is created and where?
Please be specific: what are you asking for with this comment?
- The
.configis already mising from the tool and sounds like a huge scope creep. - "If I am very particular..." I guess that means that you want an option to decide on where to create the config file? But then with even less effort you can crate the file yourself if you are so particular
now mender-cli created directories, files, and all that? have I been warned?
mender-cli already creates directories and files to save the auth token, no warning
where is it documented?
Can you please guide me on where to document it? --help?
|
For those missing a lot of functionality in It has first-class PAT token support, artifact/release/deployment/device/inventory support and a solid rewrite of the code base, based on the latest Openapi specs. We are using it in production (both developers and operational folks) for several months now. |
Hi @lluiscampos ... Check out our fork at https://github.com/Octave-Energy/mender-cli. I would be more then happy to incorporate any useful/missing feature you might think of. ➜ mender-cli git:(master) mender-cli token show
Using configuration file: /Users/me/.mender-clirc
Header:
Algorithm: RS256
Key ID: 0
Type: JWT
Payload:
Add-ons: [{"enabled":false,"name":"configure"},{"enabled":true,"name":"troubleshoot"},{"enabled":false,"name":"monitor"}]
Issued At: 2026-04-27T11:42:08Z (82 days ago)
Issuer: eu.hosted.mender.io
JWT ID: 47565c20-737c-409b-88f8-551a62b25936
Not Before: 2026-04-27T11:42:08Z (82 days ago)
Plan: os
Scope: mender.*
Subject: be64faf2-d77f-4920-9e0a-52b9af50668d
Tenant: 66849d4850f45af02136eb2f
Trial: false
User: true
As you can see, that information is available in the JWT token itself... the
Is your use case that your are regularly switching between servers? In that case it might be useful to save multiple tokens (valid on different servers) and create a |
|
Hi @boeboe and thank you very much for shipping in into the discussion and for your effort in improving the tool with your fork. Open source projects like Mender have a lot of different stakeholders to satisfy, and it is hard to keep up with all contributed PRs. Granted... I am a bit frustrated with this trivial PR... but having been there I have quite a bit of empathy for the guys 😊 I've been trying your fork. See answers below.
Note that this is true for hosted Mender, but on an Open Source installation the issuer is
Actually my use case was not different servers but just EU hosted Mender (which is the frustrating part: this is an official hosted Mender installation and mender-cli official tool should treat it as a first class use case!) Unfortunately, your code won't work out of the box. See the following: So I would still need to modify the code in your fork for the tool to get the server url from the token issuer (when existing). I believe this is quite a deep change so I rather stick to the config file modification. |
|
The errors seem fairly clear to me: FWIW, we use EU Hosted Mender as well and haven't had any problems with this setup. In fact, your last command also shows that the EU endpoint works correctly once the server is specified. And as documented, you normally don't need to pass Looking back at the original request, I think the important distinction is between runtime options and persistent configuration. If there is a desire to manage persistent configuration through the CLI, I think a more conventional approach would be something along the lines of:
and perhaps corresponding That said, given that the configuration file is very simple and that most users—including in your described use case—aren't regularly switching between Mender servers, I'm not sure there is currently enough benefit to justify adding that functionality. So I think there are really two separate questions here:
A dedicated configuration command would be a cleaner way to solve the latter if there is sufficient demand for it. |
|
Hi @boeboe And thanks for the good discussion
Right, from your first feedback:
I understood it as "we can take the JWT issuer to figure out the correct server URL" -> so what I was trying to demonstrate is that it didn't work that way with your fork (but yeah, now I understand that I got your suggestion wrong in the first place)
That is true for any server, not EU hosted Mender. As long as you write the url in the config file, is treated the same way. But that is not the case for USA hosted Mender, which is the default and works with no config. (which is obvious, the tool must have one single default)
I disagree. As an example when I do "docker login my.custom.registry" the tool saves some metadata together with the token so that when I do "docker pull" I don't need to specify the registry in the CLI options (nor manually write a config file). My point was not on the just passing --server, but the fact that login command already saves a token so it should remember the url of the server that token belongs. I am closing the PR nevertheless - it's is aging badly 👴 If the team at Mender sees any value on this they are free to pick it up. |
After a successful login with an explicit --server pointing to something different than hosted.mender.io, create or update .mender-clirc for further commands to use.