registry: allow creating new and using existing registries
This commit is contained in:
parent
81eb65ade7
commit
eafae0073a
@ -62,7 +62,7 @@ func NewCmdRegistryCreate() *cobra.Command {
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if err := client.RegistryConnect(cmd.Context(), runtimes.SelectedRuntime, regNode, clusters); err != nil {
|
||||
if err := client.RegistryConnectClusters(cmd.Context(), runtimes.SelectedRuntime, regNode, clusters); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
},
|
||||
|
@ -137,17 +137,33 @@ func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *conf
|
||||
* Step 3: Registries
|
||||
*/
|
||||
|
||||
// Ensure referenced registries
|
||||
for _, reg := range clusterConfig.ClusterCreateOpts.Registries.Use {
|
||||
regNode, err := runtime.GetNode(ctx, &k3d.Node{Name: reg.Host})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to find registry node '%s': %+v", reg.Host, err)
|
||||
}
|
||||
regFromNode, err := RegistryFromNode(regNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*reg = *regFromNode
|
||||
}
|
||||
|
||||
// Create managed registry bound to this cluster
|
||||
if clusterConfig.ClusterCreateOpts.Registries.Create != nil {
|
||||
if _, err := RegistryCreate(ctx, runtime, clusterConfig.ClusterCreateOpts.Registries.Create); err != nil {
|
||||
registryNode, err := RegistryCreate(ctx, runtime, clusterConfig.ClusterCreateOpts.Registries.Create)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create registry: %+v", err)
|
||||
}
|
||||
|
||||
clusterConfig.Cluster.Nodes = append(clusterConfig.Cluster.Nodes, registryNode)
|
||||
|
||||
clusterConfig.ClusterCreateOpts.Registries.Use = append(clusterConfig.ClusterCreateOpts.Registries.Use, clusterConfig.ClusterCreateOpts.Registries.Create)
|
||||
}
|
||||
|
||||
// Use existing registries (including the new one, if created)
|
||||
log.Debugf("Using Registries: %+v", clusterConfig.ClusterCreateOpts.Registries.Use)
|
||||
log.Tracef("Using Registries: %+v", clusterConfig.ClusterCreateOpts.Registries.Use)
|
||||
|
||||
if len(clusterConfig.ClusterCreateOpts.Registries.Use) > 0 {
|
||||
// ensure that all selected registries exist and connect them to the cluster network
|
||||
@ -156,7 +172,7 @@ func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *conf
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to find registry node '%s': %+v", externalReg.Host, err)
|
||||
}
|
||||
if err := RegistryConnect(ctx, runtime, regNode, []*k3d.Cluster{&clusterConfig.Cluster}); err != nil {
|
||||
if err := RegistryConnectNetworks(ctx, runtime, regNode, []string{clusterConfig.Cluster.Network.Name}); err != nil {
|
||||
return fmt.Errorf("Failed to connect registry node '%s' to cluster network: %+v", regNode.Name, err)
|
||||
}
|
||||
}
|
||||
|
@ -99,8 +99,8 @@ func RegistryCreate(ctx context.Context, runtime runtimes.Runtime, reg *k3d.Regi
|
||||
|
||||
}
|
||||
|
||||
// RegistryConnect connects an existing registry to one or more clusters
|
||||
func RegistryConnect(ctx context.Context, runtime runtimes.Runtime, registryNode *k3d.Node, clusters []*k3d.Cluster) error {
|
||||
// RegistryConnectClusters connects an existing registry to one or more clusters
|
||||
func RegistryConnectClusters(ctx context.Context, runtime runtimes.Runtime, registryNode *k3d.Node, clusters []*k3d.Cluster) error {
|
||||
|
||||
// find registry node
|
||||
registryNode, err := NodeGet(ctx, runtime, registryNode)
|
||||
@ -114,7 +114,7 @@ func RegistryConnect(ctx context.Context, runtime runtimes.Runtime, registryNode
|
||||
for _, c := range clusters {
|
||||
cluster, err := ClusterGet(ctx, runtime, c)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to connect to cluster '%s': Cluster not found", cluster.Name)
|
||||
log.Warnf("Failed to connect to cluster '%s': Cluster not found", c.Name)
|
||||
failed++
|
||||
continue
|
||||
}
|
||||
@ -132,6 +132,33 @@ func RegistryConnect(ctx context.Context, runtime runtimes.Runtime, registryNode
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegistryConnectNetworks connects an existing registry to one or more networks
|
||||
func RegistryConnectNetworks(ctx context.Context, runtime runtimes.Runtime, registryNode *k3d.Node, networks []string) error {
|
||||
|
||||
// find registry node
|
||||
registryNode, err := NodeGet(ctx, runtime, registryNode)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to find registry node '%s'", registryNode.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
// get cluster details and connect
|
||||
failed := 0
|
||||
for _, net := range networks {
|
||||
if err := runtime.ConnectNodeToNetwork(ctx, registryNode, net); err != nil {
|
||||
log.Warnf("Failed to connect to network '%s': Connection failed", net)
|
||||
log.Warnln(err)
|
||||
failed++
|
||||
}
|
||||
}
|
||||
|
||||
if failed > 0 {
|
||||
return fmt.Errorf("Failed to connect to one or more networks")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegistryGenerateK3sConfig generates the k3s specific registries.yaml configuration for multiple registries
|
||||
func RegistryGenerateK3sConfig(ctx context.Context, registries []*k3d.Registry) (*k3s.Registry, error) {
|
||||
regConf := &k3s.Registry{}
|
||||
@ -178,3 +205,34 @@ func RegistryGet(ctx context.Context, runtime runtimes.Runtime, name string) (*k
|
||||
return registry, nil
|
||||
|
||||
}
|
||||
|
||||
// RegistryFromNode transforms a node spec to a registry spec
|
||||
func RegistryFromNode(node *k3d.Node) (*k3d.Registry, error) {
|
||||
registry := &k3d.Registry{
|
||||
Host: node.Name,
|
||||
Image: node.Image,
|
||||
}
|
||||
|
||||
// we expect exactly one portmap
|
||||
if len(node.Ports) != 1 {
|
||||
return nil, fmt.Errorf("Failed to parse registry spec from node %+v: 0 or multiple ports defined, where one is expected", node)
|
||||
}
|
||||
|
||||
for port, bindings := range node.Ports {
|
||||
registry.ExposureOpts.Port = port
|
||||
|
||||
// we expect 0 or 1 binding for that port
|
||||
if len(bindings) > 1 {
|
||||
return nil, fmt.Errorf("Failed to parse registry spec from node %+v: Multiple bindings '%+v' specified for port '%s' where one is expected", node, bindings, port)
|
||||
}
|
||||
|
||||
for _, binding := range bindings {
|
||||
registry.ExposureOpts.Binding = binding
|
||||
}
|
||||
}
|
||||
|
||||
log.Tracef("Got registry %+v from node %+v", registry, node)
|
||||
|
||||
return registry, nil
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ import (
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
"github.com/rancher/k3d/v4/pkg/util"
|
||||
"github.com/rancher/k3d/v4/version"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// TransformSimpleToClusterConfig transforms a simple configuration to a full-fledged cluster configuration
|
||||
@ -235,6 +237,15 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
}
|
||||
}
|
||||
|
||||
for _, usereg := range simpleConfig.Registries.Use {
|
||||
reg, err := util.ParseRegistryRef(usereg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse use-registry string '%s': %+v", usereg, err)
|
||||
}
|
||||
log.Tracef("Parsed registry reference: %+v", reg)
|
||||
clusterCreateOpts.Registries.Use = append(clusterCreateOpts.Registries.Use, reg)
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Kubeconfig Options *
|
||||
**********************/
|
||||
|
@ -61,6 +61,7 @@ var ReadyLogMessageByRole = map[Role]string{
|
||||
ServerRole: "k3s is up and running",
|
||||
AgentRole: "Successfully registered node",
|
||||
LoadBalancerRole: "start worker processes",
|
||||
RegistryRole: "listening on",
|
||||
}
|
||||
|
||||
// NodeWaitForLogMessageRestartWarnTime is the time after which to warn about a restarting container
|
||||
@ -372,3 +373,12 @@ type Registry struct {
|
||||
} `yaml:"proxy,omitempty" json:"proxy,omitempty"`
|
||||
} `yaml:"options,omitempty" json:"options,omitempty"`
|
||||
}
|
||||
|
||||
// RegistryExternal describes a minimal spec for an "external" registry
|
||||
// "external" meaning, that it's unrelated to the current cluster
|
||||
// e.g. used for the --registry-use flag registry reference
|
||||
type RegistryExternal struct {
|
||||
Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"` // default: http
|
||||
Host string `yaml:"host" json:"host"`
|
||||
Port string `yaml:"port" json:"port"`
|
||||
}
|
||||
|
60
pkg/util/registry.go
Normal file
60
pkg/util/registry.go
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright © 2020 The k3d Author(s)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
)
|
||||
|
||||
var registryRefRegexp = regexp.MustCompile(`^(?P<protocol>http:\/\/|https:\/\/)?(?P<hostref>(?P<hostip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?P<hostname>[a-zA-Z\-\.0-9]+)){1}?((:)(?P<internalport>\d{1,5}))?((:)(?P<externalport>\d{1,5}))?$`)
|
||||
|
||||
// ParseRegistryRef returns a registry struct parsed from a simplified definition string
|
||||
func ParseRegistryRef(registryRef string) (*k3d.Registry, error) {
|
||||
match := registryRefRegexp.FindStringSubmatch(registryRef)
|
||||
|
||||
if len(match) == 0 {
|
||||
return nil, fmt.Errorf("Failed to parse registry reference %s: Must be [proto://]host[:port]", registryRef)
|
||||
}
|
||||
|
||||
submatches := MapSubexpNames(registryRefRegexp.SubexpNames(), match)
|
||||
|
||||
registry := &k3d.Registry{
|
||||
Host: submatches["hostref"],
|
||||
Protocol: submatches["protocol"],
|
||||
ExposureOpts: k3d.ExposureOpts{},
|
||||
}
|
||||
registry.ExposureOpts.Host = submatches["hostref"]
|
||||
|
||||
if submatches["port"] != "" {
|
||||
registry.ExposureOpts.PortMapping = nat.PortMapping{
|
||||
Port: nat.Port(fmt.Sprintf("%s/tcp", submatches["internalport"])),
|
||||
Binding: nat.PortBinding{
|
||||
HostPort: submatches["externalport"],
|
||||
},
|
||||
}
|
||||
}
|
||||
return registry, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user