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

Generalize registry support #1097

Merged
merged 6 commits into from
Jul 3, 2019
Merged

Generalize registry support #1097

merged 6 commits into from
Jul 3, 2019

Conversation

ejizba
Copy link
Contributor

@ejizba ejizba commented Jun 28, 2019

I'm skeptical that we'll ever have time to support all of the providers listed in #869, so my goal with this PR was to make it as easy as possible for the community to add support for their provider. I used GitLab as a test subject, and I'll send out a separate PR so that you can see what that looks like.

The main things that are now generalized:

  1. A log-in wizard that allows for url/username/password
  2. Caching url/username/password across sessions
  3. Pull repos/images
  4. Set registry as default

Since the list of providers will theoretically grow and make the registries view cluttered, the default view will now be this:
Screen Shot 2019-06-28 at 10 20 49 AM

Once you select to connect one, you will see this:
Screen Shot 2019-06-28 at 10 13 53 AM

That means you will only see the providers you have connected. This is a breaking change from the previous experience and it means all users will essentially have to re-connect to their registry provider when we ship this update. Here's an example of a few registries that are connected:
Screen Shot 2019-06-28 at 10 14 20 AM
(You may notice one side-benefit of this work is that you can log in to multiple docker hub accounts 🙂)

Fixes #1091

So that it's much easier for the community to add support for more providers
src/tree/registries/registryPasswords.ts Show resolved Hide resolved
src/tree/registries/logInWizard/RegistryPasswordStep.ts Outdated Show resolved Hide resolved
src/tree/registries/logInWizard/ILogInWizardContext.ts Outdated Show resolved Hide resolved
src/tree/registries/RegistriesTreeItem.ts Outdated Show resolved Hide resolved
src/tree/registries/IRegistryProvider.ts Outdated Show resolved Hide resolved
}

await pullImages(context, node.parent.parent, node.fullTag);
await pullImages(context, node.parent.parent, node.repoNameAndTag);
}

async function pullImages(context: IActionContext, node: RegistryTreeItemBase, imageRequest: string): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not related to this PR. This function name is not apt given that it also pulls repositories.

Copy link
Member

Choose a reason for hiding this comment

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

Also the file name is confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Y'all there's only so much refactoring/file-renaming a person can do at a time 😂

With the caveat that I didn't name this, I think it's named like this because pulling a repository is technically just pulling multiple images at once.

Copy link
Contributor

@PrashanthCorp PrashanthCorp left a comment

Choose a reason for hiding this comment

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

Moving from request change to comment since I'll be OOF.

@ejizba ejizba dismissed PrashanthCorp’s stale review July 2, 2019 20:23

dismissing since he's oof

{
"command": "vscode-docker.registries.pullImage",
"when": "view == dockerRegistries && viewItem =~ /tag$/i",
"when": "view == dockerRegistries && viewItem =~ /Tag;/",
Copy link
Member

Choose a reason for hiding this comment

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

Pardon my Dockgerance (Docker + ignorance), but why are all the viewItems for the images called Tags?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's confusing naming for sure and there's no official consensus. Take this as an example:
Screen Shot 2019-07-02 at 4 37 37 PM

Generally, latest and v3 are considered tags, repo1 is considered a repository and repo1:latest and repo1:v3 are considered images.

@@ -0,0 +1,63 @@
/*---------------------------------------------------------------------------------------------
Copy link
Member

Choose a reason for hiding this comment

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

What was the design decision to create this file to parse all of the contextValues instead of letting the treeItemBase classes contain the values? I was wondering since it's a pretty different design pattern from our other repos.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to create a common pattern for context values so that people wouldn't have to edit package.json when adding new registry providers. The GitLab PR shows that. I found that the previous pattern wasn't flexible enough to support that.

@@ -29,7 +34,8 @@ export async function deployImageToAzure(context: IActionContext, node?: RemoteT
newSiteKind: AppKind.app
};
const promptSteps: AzureWizardPromptStep<IAppServiceWizardContext>[] = [];
const azureAccountTreeItem = await validateAzureAccountInstalled();
// Create a temporary azure account tree item since Azure might not be connected
Copy link
Member

Choose a reason for hiding this comment

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

Connected as in the user isn't logged in yet? Or is there special work to have Azure integrated with Docker (similar to GitHub?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Connected is referencing the "registries" view. You can deploy a docker hub image to azure, which means you may have never connected the Azure "registries" provider since your images are in Docker Hub, not Azure.

}
} else {
imagePath = registryTI.host;
password = await registryTI.parent.getPassword();
Copy link
Member

Choose a reason for hiding this comment

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

There used to be an error thrown here if either username or password were undefined. Does getPassword throw an error if it fails to retrieve the password from the keytar or whatever it's using?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

99% of the time there will be a username and password. It's not clear what should happen if there isn't, but I decided to err on the side of letting them deploy. There are plenty of self-hosted registries out there with weird auth schemes and I don't want to block people.

appSettings.push({ name: "DOCKER_REGISTRY_SERVER_USERNAME", value: username });
appSettings.push({ name: "DOCKER_REGISTRY_SERVER_PASSWORD", value: password });
if (username && password) {
appSettings.push({ name: "DOCKER_REGISTRY_SERVER_USERNAME", value: username });
Copy link
Member

Choose a reason for hiding this comment

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

Are these settings only needed for specific types of Registries?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only ones that need authentication. For example, there are public docker hub images. Plus you could always add these settings later yourself

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or more likely - self hosted registries might exist that don't have auth setup yet

}

const confirmUntag: string = `Are you sure you want to untag "${node.fullTag}"? This does not delete the manifest referenced by the tag.`;
const confirmUntag: string = `Are you sure you want to untag "${node.repoNameAndTag}"? This does not delete the manifest referenced by the tag.`;
Copy link
Member

Choose a reason for hiding this comment

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

Since this isn't destructive, do we need to prompt for it? I realize that you aren't the one who made it a prompt, just wondering if we needed to have it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is (partially) destructive

@@ -22,7 +23,8 @@ export async function openDockerHubInBrowser(context: IActionContext, node?: Doc
} else if (node instanceof DockerHubRepositoryTreeItem) {
url += `r/${node.parent.namespace}/${node.repoName}`;
} else {
url += `r/${node.parent.parent.namespace}/${node.parent.repoName}/tags`
const repoTI = <DockerHubRepositoryTreeItem>node.parent;
url += `r/${repoTI.parent.namespace}/${repoTI.repoName}/tags`;
Copy link
Member

Choose a reason for hiding this comment

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

Do you know why it's using += here? It doesn't look like there was anything assigned to dockerHubUrl previously anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

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

dockerHubUrl is defined in constants.ts

const terminal: Terminal = ext.terminalProvider.createTerminal('docker logout');
terminal.sendText(command);
terminal.sendText(`docker logout ${creds.registryPath}`);
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to replace all of the terminal calls with dockerode?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've considered it, but that's a pretty big refactor and I've probably already gone too far down the refactoring rabbit-hole lately

ext.registriesTree = new AzExtTreeDataProvider(registriesTreeItem, registriesLoadMore);
ext.registriesTreeView = window.createTreeView('dockerRegistries', { treeDataProvider: ext.registriesTree });
ext.registriesTree = new AzExtTreeDataProvider(ext.registriesRoot, registriesLoadMore);
ext.registriesTreeView = window.createTreeView('dockerRegistries', { treeDataProvider: ext.registriesTree, showCollapseAll: true });
Copy link
Member

Choose a reason for hiding this comment

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

🎉 🎉 🎉 🎉 🎉

break;
}
let placeHolder: string = 'Select the provider for your registry';
const provider = (await ext.ui.showQuickPick(picks, { placeHolder, suppressPersistence: true })).data;
Copy link
Member

Choose a reason for hiding this comment

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

Don't we have a learnMore property that we can leverage?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's only for warning messages, not quick picks. Also that logic will re-show the message, but there's no point of re-showing the quick pick if your provider isn't listed

@ejizba ejizba merged commit 7db7592 into master Jul 3, 2019
@ejizba ejizba deleted the ej/regV3 branch July 4, 2019 00:10
@microsoft microsoft locked and limited conversation to collaborators Oct 27, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fail to pull images from the private registry
3 participants