Skip to content

Commit

Permalink
rename to hostaliases and use rfc1123 regexp to validate hostnames
Browse files Browse the repository at this point in the history
  • Loading branch information
iwilltry42 committed Jan 27, 2022
1 parent 4f4cb81 commit d0638de
Show file tree
Hide file tree
Showing 37 changed files with 5,395 additions and 77 deletions.
40 changes: 37 additions & 3 deletions cmd/cluster/clusterCreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

"github.com/docker/go-connections/nat"
"github.com/sirupsen/logrus"
"inet.af/netaddr"

"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -266,6 +267,9 @@ func NewCmdClusterCreate() *cobra.Command {
cmd.Flags().String("registry-create", "", "Create a k3d-managed registry and connect it to the cluster (Format: `NAME[:HOST][:HOSTPORT]`\n - Example: `k3d cluster create --registry-create mycluster-registry:0.0.0.0:5432`")
_ = ppViper.BindPFlag("cli.registries.create", cmd.Flags().Lookup("registry-create"))

cmd.Flags().StringArray("host-alias", nil, "Add `ip:host[,host,...]` mappings")
_ = ppViper.BindPFlag("hostaliases", cmd.Flags().Lookup("host-alias"))

/* k3s */
cmd.Flags().StringArray("k3s-arg", nil, "Additional args passed to k3s command (Format: `ARG@NODEFILTER[;@NODEFILTER]`)\n - Example: `k3d cluster create --k3s-arg \"--disable=traefik@server:0\"")
_ = ppViper.BindPFlag("cli.k3sargs", cmd.Flags().Lookup("k3s-arg"))
Expand Down Expand Up @@ -330,9 +334,6 @@ func NewCmdClusterCreate() *cobra.Command {
cmd.Flags().Bool("host-pid-mode", false, "Enable host pid mode of server(s) and agent(s)")
_ = cfgViper.BindPFlag("options.runtime.hostpidmode", cmd.Flags().Lookup("host-pid-mode"))

cmd.Flags().StringArray("extra-host", nil, "Add `host:ip` mappings")
_ = cfgViper.BindPFlag("extraHosts", cmd.Flags().Lookup("extra-host"))

/* Image Importing */
cmd.Flags().Bool("no-image-volume", false, "Disable the creation of a volume for importing images")
_ = cfgViper.BindPFlag("options.k3d.disableimagevolume", cmd.Flags().Lookup("no-image-volume"))
Expand Down Expand Up @@ -596,8 +597,41 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) {
cfg.Registries.Create.Host = exposeAPI.Host
cfg.Registries.Create.HostPort = exposeAPI.Binding.HostPort
}
}

// --host-alias
hostAliasFlags := ppViper.GetStringSlice("hostaliases")
l.Log().Debugf("HostAliasFlags: %+v", hostAliasFlags)
if len(hostAliasFlags) > 0 {
for _, ha := range hostAliasFlags {

// split on :
s := strings.Split(ha, ":")
if len(s) != 2 {
return cfg, fmt.Errorf("invalid format of host-alias %s (exactly one ':' allowed)", ha)
}

// validate IP // TODO: move to pkg/ validate config?
ip, err := netaddr.ParseIP(s[0])
if err != nil {
return cfg, fmt.Errorf("invalid IP '%s' in host-alias '%s': %w", s[0], ha, err)
}

// hostnames
hostnames := strings.Split(s[1], ",")
for _, hostname := range hostnames {
if err := k3dCluster.ValidateHostname(hostname); err != nil {
return cfg, fmt.Errorf("invalid hostname '%s' in host-alias '%s': %w", hostname, ha, err)
}
}

cfg.HostAliases = append(cfg.HostAliases, k3d.HostAlias{
IP: ip.String(),
Hostnames: hostnames,
})
}
}
l.Log().Debugf("HostAliases: %+v", cfg.HostAliases)

return cfg, nil
}
88 changes: 39 additions & 49 deletions pkg/client/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,66 +251,56 @@ func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *conf
* -> host:ip mappings
*/

if len(clusterConfig.ClusterCreateOpts.ExtraHosts) > 0 {
if len(clusterConfig.ClusterCreateOpts.HostAliases) > 0 {

extraHostsMap := map[string][]string{}
for _, extraHost := range clusterConfig.ClusterCreateOpts.ExtraHosts {
s := strings.Split(extraHost, ":")
if len(s) != 2 {
return fmt.Errorf("extra host entry '%s' had invalid format", extraHost)
}
extraHostsMap[s[1]] = append(extraHostsMap[s[1]], s[0])
}

if len(extraHostsMap) > 0 {
extraHostsInjectEtcHostsHook := k3d.NodeHook{
Stage: k3d.LifecycleStagePostStart,
Action: actions.RewriteFileAction{
Runtime: runtime,
Path: "/etc/hosts",
Mode: 0644,
Description: "Adding ExtraHosts to /etc/hosts in nodes",
Opts: actions.RewriteFileActionOpts{
NoCopy: true,
},
RewriteFunc: func(input []byte) ([]byte, error) {
hostAliasesInjectEtcHostsHook := k3d.NodeHook{
Stage: k3d.LifecycleStagePostStart,
Action: actions.RewriteFileAction{
Runtime: runtime,
Path: "/etc/hosts",
Mode: 0644,
Description: "Adding HostAliases to /etc/hosts in nodes",
Opts: actions.RewriteFileActionOpts{
NoCopy: true,
},
RewriteFunc: func(input []byte) ([]byte, error) {

// write copied hosts file to temp path (for hostsfile module to read)
tmpHosts, err := os.CreateTemp("", "k3d-hostsfile-*")
if err != nil {
return nil, fmt.Errorf("error creating temp hosts file: %w", err)
}
os.WriteFile(tmpHosts.Name(), input, 0777)
// write copied hosts file to temp path (for hostsfile module to read)
tmpHosts, err := os.CreateTemp("", "k3d-hostsfile-*")
if err != nil {
return nil, fmt.Errorf("error creating temp hosts file: %w", err)
}
os.WriteFile(tmpHosts.Name(), input, 0777)

// read in temp hostsfile file
hostsfile, err := hostsfile.NewCustomHosts(tmpHosts.Name())
if err != nil {
return nil, fmt.Errorf("error reading temp hosts file: %w", err)
}
// read in temp hostsfile file
hostsfile, err := hostsfile.NewCustomHosts(tmpHosts.Name())
if err != nil {
return nil, fmt.Errorf("error reading temp hosts file: %w", err)
}

// add new entries
for ip, hosts := range extraHostsMap {
if err := hostsfile.Add(ip, hosts...); err != nil {
return nil, fmt.Errorf("error adding hosts file entry for %s:%s: %w", ip, hosts, err)
}
// add new entries
for _, hostAlias := range clusterConfig.ClusterCreateOpts.HostAliases {
if err := hostsfile.Add(hostAlias.IP, hostAlias.Hostnames...); err != nil {
return nil, fmt.Errorf("error adding hosts file entry for %s:%s: %w", hostAlias.IP, hostAlias.Hostnames, err)
}
}

// cleanup (de-duplicate, etc.)
hostsfile.Clean()
// cleanup (de-duplicate, etc.)
hostsfile.Clean()

// write changes to temp file
hostsfile.Flush()
// write changes to temp file
hostsfile.Flush()

time.Sleep(time.Second)
time.Sleep(time.Second)

return os.ReadFile(tmpHosts.Name())
},
return os.ReadFile(tmpHosts.Name())
},
}

// append new action to general nodehooks
clusterConfig.ClusterCreateOpts.NodeHooks = append(clusterConfig.ClusterCreateOpts.NodeHooks, extraHostsInjectEtcHostsHook)
},
}

// append new action to general nodehooks
clusterConfig.ClusterCreateOpts.NodeHooks = append(clusterConfig.ClusterCreateOpts.NodeHooks, hostAliasesInjectEtcHostsHook)

}

return nil
Expand Down
21 changes: 6 additions & 15 deletions pkg/client/clusterName.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ package client

import (
"fmt"
"regexp"

"github.com/rancher/k3d/v5/pkg/types"
)

// HostnameRegexp as per RFC 1123
var HostnameRegexp = regexp.MustCompile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`)

// CheckName ensures that a cluster name is also a valid host name according to RFC 1123.
// We further restrict the length of the cluster name to maximum 'clusterNameMaxSize'
// so that we can construct the host names based on the cluster name, and still stay
Expand All @@ -48,21 +52,8 @@ func ValidateHostname(name string) error {
return fmt.Errorf("No name provided")
}

if name[0] == '-' || name[len(name)-1] == '-' {
return fmt.Errorf("Hostname '%s' must not start or end with '-' (dash)", name)
}

for _, c := range name {
switch {
case '0' <= c && c <= '9':
case 'a' <= c && c <= 'z':
case 'A' <= c && c <= 'Z':
case c == '-':
break
default:
return fmt.Errorf("Hostname '%s' contains characters other than 'Aa-Zz', '0-9' or '-'", name)

}
if !HostnameRegexp.Match([]byte(name)) {
return fmt.Errorf("name %s is not a valid hostname as per RFC 1123", name)
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
GPURequest: simpleConfig.Options.Runtime.GPURequest,
ServersMemory: simpleConfig.Options.Runtime.ServersMemory,
AgentsMemory: simpleConfig.Options.Runtime.AgentsMemory,
ExtraHosts: simpleConfig.ExtraHosts,
HostAliases: simpleConfig.HostAliases,
GlobalLabels: map[string]string{}, // empty init
GlobalEnv: []string{}, // empty init
}
Expand Down
20 changes: 14 additions & 6 deletions pkg/config/v1alpha3/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,22 @@
"additionalProperties": false
}
},
"extraHosts": {
"hostAliases": {
"type": "array",
"description": "Additional host:ip mappings in format `my.host.domain:1.2.3.4`",
"description": "Additional IP to multiple hostnames mappings",
"items": {
"type": "string",
"examples": [
"my.host.domain:1.2.3.4"
]
"type": "object",
"properties": {
"ip": {
"type": "string"
},
"hostnames": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion pkg/config/v1alpha3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"time"

config "github.com/rancher/k3d/v5/pkg/config/types"
"github.com/rancher/k3d/v5/pkg/types"
k3d "github.com/rancher/k3d/v5/pkg/types"
"github.com/rancher/k3d/v5/version"
)
Expand Down Expand Up @@ -155,7 +156,7 @@ type SimpleConfig struct {
Options SimpleConfigOptions `mapstructure:"options" yaml:"options,omitempty" json:"options,omitempty"`
Env []EnvVarWithNodeFilters `mapstructure:"env" yaml:"env,omitempty" json:"env,omitempty"`
Registries SimpleConfigRegistries `mapstructure:"registries" yaml:"registries,omitempty" json:"registries,omitempty"`
ExtraHosts []string `mapstructure:"extraHosts" yaml:"extraHosts,omitempty" json:"extraHosts,omitempty"`
HostAliases []types.HostAlias `mapstructure:"hostAliases" yaml:"hostAliases,omitempty" json:"hostAliases,omitempty"`
}

type SimpleConfigIntermediateV1alpha2 struct {
Expand Down
9 changes: 7 additions & 2 deletions pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ var DoNotCopyServerFlags = []string{
"--cluster-init",
}

type HostAlias struct {
IP string `mapstructure:"ip" yaml:"ip" json:"ip"`
Hostnames []string `mapstructure:"hostnames" yaml:"hostnames" json:"hostnames"`
}

// ClusterCreateOpts describe a set of options one can set when creating a cluster
type ClusterCreateOpts struct {
DisableImageVolume bool `yaml:"disableImageVolume" json:"disableImageVolume,omitempty"`
Expand All @@ -113,7 +118,7 @@ type ClusterCreateOpts struct {
NodeHooks []NodeHook `yaml:"nodeHooks,omitempty" json:"nodeHooks,omitempty"`
GlobalLabels map[string]string `yaml:"globalLabels,omitempty" json:"globalLabels,omitempty"`
GlobalEnv []string `yaml:"globalEnv,omitempty" json:"globalEnv,omitempty"`
ExtraHosts []string `yaml:"extraHosts,omitempty" json:"extraHosts,omitempty"`
HostAliases []HostAlias `yaml:"hostAliases,omitempty" json:"hostAliases,omitempty"`
Registries struct {
Create *Registry `yaml:"create,omitempty" json:"create,omitempty"`
Use []*Registry `yaml:"use,omitempty" json:"use,omitempty"`
Expand Down Expand Up @@ -289,7 +294,7 @@ type Node struct {
RuntimeLabels map[string]string `yaml:"runtimeLabels" json:"runtimeLabels,omitempty"`
K3sNodeLabels map[string]string `yaml:"k3sNodeLabels" json:"k3sNodeLabels,omitempty"`
Networks []string // filled automatically
ExtraHosts []string // filled automatically
ExtraHosts []string // filled automatically (docker specific?)
ServerOpts ServerOpts `yaml:"serverOpts" json:"serverOpts,omitempty"`
AgentOpts AgentOpts `yaml:"agentOpts" json:"agentOpts,omitempty"`
GPURequest string // filled automatically
Expand Down
15 changes: 15 additions & 0 deletions vendor/github.com/asaskevich/govalidator/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions vendor/github.com/asaskevich/govalidator/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions vendor/github.com/asaskevich/govalidator/CODE_OF_CONDUCT.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d0638de

Please sign in to comment.