Implement the --cert-name flag to select a lineage by its name.#3785
Implement the --cert-name flag to select a lineage by its name.#3785ohemorange merged 26 commits intomasterfrom
Conversation
|
Pushing to github to see missing comment updates and test coverage, not ready for review. |
|
Update: this also contains a Once coverage and tests are happy I expect this to be ready for review. |
|
Test 1: I have an
But I was interactively prompted for an authenticator, which I didn't expect. I then tried
In this case the renewal appeared to work, but I got mysterious behavior on the install attempt: (Also not sure why I can get "Congratulations" with the error: I guess because auth worked but install didn't?) Can any of these behaviors be attributed to this PR? I can try to run the same commands with an older branch for comparison. |
schoen
left a comment
There was a problem hiding this comment.
These are all textual/documentation related but I also wonder if you can repeat my tests in an environment of your own and see if you get the same problems, or if it succeeds for you.
certbot/cert_manager.py
Outdated
|
|
||
| """ | ||
| if not config.certname: | ||
| raise errors.ConfigurationError("Specify a certificate name with " |
There was a problem hiding this comment.
I think this might be clearer as "Specify an existing certificate name with" (for parallelism with the other message).
| [None, "run", "certonly"], | ||
| "--cert-name", dest="certname", | ||
| metavar="CERTNAME", default=None, | ||
| help="Certificate name to apply. Only one certificate name can be used " |
There was a problem hiding this comment.
I think the switch between addressees of the imperative verbs here ("Show certificate names" and "create a new certificate") will confuse readers, because one is saying "[you can] show certificate names by..." and the other is saying "[the program will] create a new certificate...".
Could we change the text for the "Show certificate names" sentence to something like
(You can see certificate names by running certificates command.)
or
(To see certificate names, run certificates command.)
or
(Names can be found with the certificates command.)?
There was a problem hiding this comment.
Yes and maybe also better to say something like by running "certbot certificates" or by running cerbot with the "certificates" subcommand?
There was a problem hiding this comment.
Good call. I like To see certificate names, run "certbot certificates".
| logger.debug("Traceback was:\n%s", traceback.format_exc()) | ||
| continue | ||
| rv = func(candidate_lineage, rv) | ||
| return rv |
There was a problem hiding this comment.
I was originally wondering about the case where there's more than one matching lineage and whether we'd simply get func() of the last one, but now I see that since the intermediate rv is an argument to func, someone writing a func could also choose to have it accumulate values as it goes, like in a list, if they want information about multiple lineages. So, nice, flexible design there.
There was a problem hiding this comment.
Flexibility is my goal! I'll put this in the docstring to make it clear.
| helpful.add( | ||
| "rename", | ||
| "--new-cert-name", dest="new_certname", | ||
| metavar="NEW_CERTNAME", default=None, |
There was a problem hiding this comment.
Is it valid to use only --new-cert-name with a new lineage, instead of --cert-name? (Are they synonyms when there is no existing lineage with the specified name?) I can definitely imagine some users mentally parsing this as (new-cert)-name instead of new-(cert-name) and so trying to use it in that case.
There was a problem hiding this comment.
Oh good point. Maybe --updated-cert-name is better? Or just --new-certname and then also call it --certname in other places? I don't want to make this flag for anything other than setting a new cert name.
| helpful.add( | ||
| "automation", "--renew-with-new-domains", | ||
| action="store_true", dest="renew_with_new_domains", help="If a " | ||
| "certificate already exists for the requested certificate name " |
There was a problem hiding this comment.
should probably be "requested domains" here
| question = ( | ||
| "You have an existing certificate that contains exactly the same " | ||
| "domains you requested and isn't close to expiry." | ||
| "domains or certificate name you requested and isn't close to expiry." |
There was a problem hiding this comment.
Maybe this would be clearer as "has exactly the same domains or certificate name", since people might not think of the certificate as "containing" its own certificate name? (At least knowing the implementation details, I don't.)
There was a problem hiding this comment.
If you're feeling fancy, provide a question whose wording varies depending on whether the user actually provided domains or a certificate name (or if you agree that's a good idea but don't want to do it in this PR, open a new ticket for it).
There was a problem hiding this comment.
I'll put it to has for now.
| """ | ||
| if config.renew_with_new_domains: | ||
| return | ||
| msg = ("Confirm that you intend to update certificate {0} " |
There was a problem hiding this comment.
Would it be helpful or unhelpful to put quotes around the lineage name when displaying it?
There was a problem hiding this comment.
I have no opinion about this. Let me know if you want me to change it.
There was a problem hiding this comment.
I guess I'm also not sure, so I won't suggest a change.
certbot/storage.py
Outdated
| return config | ||
|
|
||
| def rename_renewal_config(prev_name, new_name, cli_config): | ||
| """Rename's cli_config.certname's config to cli_config.new_certname. |
pde
left a comment
There was a problem hiding this comment.
A couple of changes requested to use the IDisplay mechanisms for [non]interactivity in standard ways, plus a small change in storage, plus some nits/optional suggestions.
certbot/main.py
Outdated
| new_domains, | ||
| old_domains)) | ||
| obj = zope.component.getUtility(interfaces.IDisplay) | ||
| if not obj.yesno(msg, "Update cert", "Cancel"): |
There was a problem hiding this comment.
Thanks to @PaulSD for noticing this: you should add default=True to this obj.yesno() call, so that this path can be run non-interactively.
There was a problem hiding this comment.
I had added a cli flag because I didn't know about this default=True thing. It seems like we usually have both a noninteractive option and a cli flag, is that right? Or should I remove the cli flag given that it can be run noninteractively?
There was a problem hiding this comment.
Good question. In most cases the CLI flags of that sort (like --keep-until-expiring) predated the -n flag, so we've never asked ourselves that question!
Argument 1: -n does the job, so let's just make everyone use it if they want non-interactive execution
Argument 2: the user might want to be asked about --domains interactively, but not this update confirm thing, so they might want to provide the flag for "Update" on the command line (or put it in /etc/letsencrypt/cli.ini) while still running interactively.
Which do we find more persuasive?
There was a problem hiding this comment.
Let's keep both, because a user might not know about non-interactive mode and just look for the specific command-line flag they want.
There was a problem hiding this comment.
While I don't feel strongly, I think it is the user's responsibility to look at the documentation of the available flags more closely if (s)he doesn't immediately find what (s)he needs.
Furthermore, if you're running in interactive mode, I don't think it is so bad to get an extra question; in other words, I don't think there needs to be a switch to mute specific aspects of the interactive mode. (The number of questions is low anyways.) It's a trade-off with code simplicity, which I also consider valuable.
certbot/cert_manager.py
Outdated
| raise errors.ConfigurationError("Specify a certificate name with " | ||
| "with flag --cert-name.") | ||
| if not config.new_certname: | ||
| raise errors.ConfigurationError("Specify a new name for certificate {0} " |
There was a problem hiding this comment.
This should be errors.MissingCommandlineFlag.
But even better would be to do something like calling disp.input("Enter the new name for certificate {0}".format(config.certname), flag="--new-cert-name"). That will raise a nicely formatted errors.MissingCommandlineFlag for you.
There was a problem hiding this comment.
ah! I didn't know we had that but I like it!
There was a problem hiding this comment.
In addition, the previous check can probably provide a list of cert names.
There was a problem hiding this comment.
ok it now does that.
certbot/cert_manager.py
Outdated
| def lineage_for_certname(config, certname): | ||
| """Find a lineage object with name certname. | ||
| """ | ||
| def func(candidate_lineage, rv): |
There was a problem hiding this comment.
Style nit: Maybe nicer to call this matches_certname or certname_match_fn or something?
There was a problem hiding this comment.
This function returns a lineage object for a given certname. Is it that the name is too long?
There was a problem hiding this comment.
My nit was suggesting something slightly more descriptive instead of func. But feel free to ignore this suggestion!
There was a problem hiding this comment.
Oh that makes more sense! I can do that.
| [None, "run", "certonly"], | ||
| "--cert-name", dest="certname", | ||
| metavar="CERTNAME", default=None, | ||
| help="Certificate name to apply. Only one certificate name can be used " |
There was a problem hiding this comment.
Yes and maybe also better to say something like by running "certbot certificates" or by running cerbot with the "certificates" subcommand?
|
|
||
| def _auth_from_domains(le_client, config, domains, lineage=None): | ||
| def _auth_from_available(le_client, config, domains=None, certname=None, lineage=None): | ||
| """Authenticate and enroll certificate. |
There was a problem hiding this comment.
Maybe we should document what is going on here a little bit more?
There was a problem hiding this comment.
Ha yes. Especially given that this is the primary main authentication method, as far as I can tell.
There was a problem hiding this comment.
Yup; it was already mysterious, and is becoming more so :)
There was a problem hiding this comment.
How do you feel about the current documentation?
| question = ( | ||
| "You have an existing certificate that contains exactly the same " | ||
| "domains you requested and isn't close to expiry." | ||
| "domains or certificate name you requested and isn't close to expiry." |
There was a problem hiding this comment.
If you're feeling fancy, provide a question whose wording varies depending on whether the user actually provided domains or a certificate name (or if you agree that's a good idea but don't want to do it in this PR, open a new ticket for it).
certbot/storage.py
Outdated
| cli_config.renewal_configs_dir, prev_name) + ".conf" | ||
| new_filename = os.path.join( | ||
| cli_config.renewal_configs_dir, new_name) + ".conf" | ||
| if os.path.isfile(new_filename): |
There was a problem hiding this comment.
I think this should probably be os.path.exists(new_filename), so that it errors on directories, links, etc.
|
@ohemorange, yes, I'll try getting a new lineage with master, then running the closest equivalents to those, then running those with this branch, and see if the problem recurs or not. |
certbot/tests/cert_manager_test.py
Outdated
| self.assertTrue(mock_renewer_config) | ||
|
|
||
|
|
||
| class RenameLineageTest(storage_test.BaseRenewableCertTest): |
There was a problem hiding this comment.
There's a BaseCertManagerTest that will work here, why not use that?
There was a problem hiding this comment.
What a good idea, I should do that!
|
Make coveralls report back? |
Step 3 of #3615.