[FIX/ENHANCEMENT] node/create: inherit registry config from existing nodes (#597)

This commit is contained in:
Thorsten Klein 2021-05-11 08:17:58 +02:00 committed by GitHub
parent 5fe8a3c6c7
commit bb1f5bde71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 5 deletions

View File

@ -25,7 +25,9 @@ package client
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"reflect" "reflect"
"strings" "strings"
@ -33,8 +35,10 @@ import (
dockerunits "github.com/docker/go-units" dockerunits "github.com/docker/go-units"
"github.com/imdario/mergo" "github.com/imdario/mergo"
"github.com/rancher/k3d/v4/pkg/actions"
"github.com/rancher/k3d/v4/pkg/runtimes" "github.com/rancher/k3d/v4/pkg/runtimes"
"github.com/rancher/k3d/v4/pkg/runtimes/docker" "github.com/rancher/k3d/v4/pkg/runtimes/docker"
runtimeErrors "github.com/rancher/k3d/v4/pkg/runtimes/errors"
k3d "github.com/rancher/k3d/v4/pkg/types" k3d "github.com/rancher/k3d/v4/pkg/types"
"github.com/rancher/k3d/v4/pkg/util" "github.com/rancher/k3d/v4/pkg/util"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -89,6 +93,25 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
log.Debugf("Adding node %+v \n>>> to cluster %+v\n>>> based on existing node %+v", node, cluster, chosenNode) log.Debugf("Adding node %+v \n>>> to cluster %+v\n>>> based on existing node %+v", node, cluster, chosenNode)
// fetch registry config
registryConfigBytes := []byte{}
registryConfigReader, err := runtime.ReadFromNode(ctx, k3d.DefaultRegistriesFilePath, chosenNode)
if err != nil {
if !errors.Is(err, runtimeErrors.ErrRuntimeFileNotFound) {
log.Warnf("Failed to read registry config from node %s: %+v", node.Name, err)
}
} else {
defer registryConfigReader.Close()
var err error
registryConfigBytes, err = ioutil.ReadAll(registryConfigReader)
if err != nil {
log.Warnf("Failed to read registry config from node %s: %+v", node.Name, err)
}
registryConfigReader.Close()
registryConfigBytes = bytes.Trim(registryConfigBytes[512:], "\x00") // trim control characters, etc.
}
// merge node config of new node into existing node config // merge node config of new node into existing node config
if err := mergo.MergeWithOverwrite(chosenNode, *node); err != nil { if err := mergo.MergeWithOverwrite(chosenNode, *node); err != nil {
log.Errorln("Failed to merge new node config into existing node config") log.Errorln("Failed to merge new node config into existing node config")
@ -133,11 +156,27 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
} }
} }
// add node actions
if len(registryConfigBytes) != 0 {
if createNodeOpts.NodeHooks == nil {
createNodeOpts.NodeHooks = []k3d.NodeHook{}
}
createNodeOpts.NodeHooks = append(createNodeOpts.NodeHooks, k3d.NodeHook{
Stage: k3d.LifecycleStagePreStart,
Action: actions.WriteFileAction{
Runtime: runtime,
Content: registryConfigBytes,
Dest: k3d.DefaultRegistriesFilePath,
Mode: 0644,
},
})
}
// clear status fields // clear status fields
node.State.Running = false node.State.Running = false
node.State.Status = "" node.State.Status = ""
if err := NodeRun(ctx, runtime, node, k3d.NodeCreateOpts{}); err != nil { if err := NodeRun(ctx, runtime, node, createNodeOpts); err != nil {
return err return err
} }
@ -162,7 +201,7 @@ func NodeAddToClusterMulti(ctx context.Context, runtime runtimes.Runtime, nodes
nodeWaitGroup, ctx := errgroup.WithContext(ctx) nodeWaitGroup, ctx := errgroup.WithContext(ctx)
for _, node := range nodes { for _, node := range nodes {
if err := NodeAddToCluster(ctx, runtime, node, cluster, k3d.NodeCreateOpts{}); err != nil { if err := NodeAddToCluster(ctx, runtime, node, cluster, createNodeOpts); err != nil {
return err return err
} }
if createNodeOpts.Wait { if createNodeOpts.Wait {
@ -230,8 +269,9 @@ func NodeRun(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, node
} }
if err := NodeStart(ctx, runtime, node, k3d.NodeStartOpts{ if err := NodeStart(ctx, runtime, node, k3d.NodeStartOpts{
Wait: nodeCreateOpts.Wait, Wait: nodeCreateOpts.Wait,
Timeout: nodeCreateOpts.Timeout, Timeout: nodeCreateOpts.Timeout,
NodeHooks: nodeCreateOpts.NodeHooks,
}); err != nil { }); err != nil {
return err return err
} }

View File

@ -26,6 +26,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"io"
"os" "os"
"strings" "strings"
@ -35,6 +36,7 @@ import (
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/pkg/errors" "github.com/pkg/errors"
runtimeErrors "github.com/rancher/k3d/v4/pkg/runtimes/errors"
k3d "github.com/rancher/k3d/v4/pkg/types" k3d "github.com/rancher/k3d/v4/pkg/types"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -140,6 +142,30 @@ func (d Docker) WriteToNode(ctx context.Context, content []byte, dest string, mo
return nil return nil
} }
// ReadFromNode reads from a given filepath inside the node container
func (d Docker) ReadFromNode(ctx context.Context, path string, node *k3d.Node) (io.ReadCloser, error) {
log.Tracef("Reading path %s from node %s...", path, node.Name)
nodeContainer, err := getNodeContainer(ctx, node)
if err != nil {
return nil, fmt.Errorf("Failed to find container for node '%s': %+v", node.Name, err)
}
docker, err := GetDockerClient()
if err != nil {
return nil, err
}
reader, _, err := docker.CopyFromContainer(ctx, nodeContainer.ID, path)
if err != nil {
if client.IsErrNotFound(err) {
return nil, errors.Wrap(runtimeErrors.ErrRuntimeFileNotFound, err.Error())
}
return nil, err
}
return reader, err
}
// GetDockerClient returns a docker client // GetDockerClient returns a docker client
func GetDockerClient() (*client.Client, error) { func GetDockerClient() (*client.Client, error) {
var err error var err error

View File

@ -19,7 +19,7 @@ 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
package runtimes package errors
import "errors" import "errors"
@ -34,3 +34,6 @@ var (
ErrRuntimeNetworkNotExists = errors.New("network does not exist") ErrRuntimeNetworkNotExists = errors.New("network does not exist")
ErrRuntimeNetworkMultiSameName = errors.New("multiple networks with same name found") ErrRuntimeNetworkMultiSameName = errors.New("multiple networks with same name found")
) )
// Container Filesystem Errors
var ErrRuntimeFileNotFound = errors.New("file not found")

View File

@ -71,6 +71,7 @@ type Runtime interface {
GetImages(context.Context) ([]string, error) GetImages(context.Context) ([]string, error)
CopyToNode(context.Context, string, string, *k3d.Node) error // @param context, source, destination, node CopyToNode(context.Context, string, string, *k3d.Node) error // @param context, source, destination, node
WriteToNode(context.Context, []byte, string, os.FileMode, *k3d.Node) error // @param context, content, destination, filemode, node WriteToNode(context.Context, []byte, string, os.FileMode, *k3d.Node) error // @param context, content, destination, filemode, node
ReadFromNode(context.Context, string, *k3d.Node) (io.ReadCloser, error) // @param context, filepath, node
GetHostIP(context.Context, string) (net.IP, error) GetHostIP(context.Context, string) (net.IP, error)
ConnectNodeToNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name ConnectNodeToNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name
DisconnectNodeFromNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name DisconnectNodeFromNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name