edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerUtil.cs (38 lines of code) (raw):
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Azure.Devices.Edge.Agent.Docker
{
using System;
using System.Collections.Generic;
using global::Docker.DotNet.Models;
using Microsoft.Azure.Devices.Edge.Util;
public static class DockerUtil
{
/// <summary>
/// This is the grammar for image names, from the docker codebase:
/// Grammar
///
/// reference := name [ ":" tag ] [ "@" digest ]
/// name := [domain '/'] path-component ['/' path-component]*
/// domain := domain-component ['.' domain-component]* [':' port-number]
/// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
/// port-number := /[0-9]+/
/// path-component := alpha-numeric [separator alpha-numeric]*
/// alpha-numeric := /[a-z0-9]+/
/// separator := /[_.]|__|[-]*/
///
/// tag := /[\w][\w.-]{0,127}/
///
/// digest := digest-algorithm ":" digest-hex
/// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
/// digest-algorithm-separator := /[+.-_]/
/// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
/// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
///
/// identifier := /[a-f0-9]{64}/
/// short-identifier := /[a-f0-9]{6,64}/
///
/// tl;dr if there is more than one path-component, and the first component contains a '.' or ':' then
/// it is a registry address.
/// For more information: https://github.com/docker/distribution/blob/main/reference/reference.go
/// </summary>
/// <param name="image">docker image tag</param>
/// <param name="domain">docker domain</param>
/// <returns>true if it is a valid docker image tag; otherwise false.</returns>
public static bool TryParseDomainFromImage(string image, out string domain)
{
domain = string.Empty;
string[] parts = Preconditions.CheckNotNull(image).Split('/');
if (parts.Length > 1)
{
string maybeDomain = parts[0];
if (maybeDomain.Contains(".") || maybeDomain.Contains(":"))
{
// Contains a '.' or ':' in the first component
// This must be a registry domain
domain = maybeDomain;
return true;
}
// if the first component is not a domain, it could still
// refer to a private repository on docker hub.
// return the default registry address
domain = Constants.DefaultRegistryAddress;
return true;
}
// Only one path-component in this image name
// It must be a public repository on Docker Hub
return false;
}
public static Option<AuthConfig> FirstAuthConfig(this IEnumerable<AuthConfig> authConfigs, string image)
{
Preconditions.CheckNotNull(image);
return authConfigs == null
? Option.None<AuthConfig>()
: authConfigs.FirstOption(auth => HostnameMatches(image, auth));
}
static bool HostnameMatches(string image, AuthConfig auth) =>
TryParseDomainFromImage(image, out string hostname)
? string.Compare(hostname, auth.ServerAddress, StringComparison.OrdinalIgnoreCase) == 0
: false;
}
}