fix api-port

pull/227/head
iwilltry42 5 years ago
parent af04a621c3
commit 116dd5dad8
  1. 18
      cmd/create/createCluster.go
  2. 4
      pkg/cluster/cluster.go
  3. 42
      pkg/cluster/kubeconfig.go
  4. 21
      pkg/cluster/node.go
  5. 69
      pkg/cluster/ports.go
  6. 40
      pkg/types/types.go

@ -22,8 +22,6 @@ THE SOFTWARE.
package create
import (
"fmt"
"github.com/spf13/cobra"
"github.com/rancher/k3d/pkg/cluster"
@ -120,6 +118,10 @@ func parseCreateClusterCmd(cmd *cobra.Command, args []string) (runtimes.Runtime,
if err != nil {
log.Fatalln(err)
}
exposeAPI, err := cluster.ParseAPIPort(apiPort)
if err != nil {
log.Fatalln(err)
}
// --volume
volumes, err := cmd.Flags().GetStringSlice("volume")
@ -144,14 +146,13 @@ func parseCreateClusterCmd(cmd *cobra.Command, args []string) (runtimes.Runtime,
// -> master nodes
for i := 0; i < masterCount; i++ {
node := k3d.Node{
Role: k3d.MasterRole,
Image: image,
Volumes: volumes, // add only volumes for `all`, `masters`, `master[i]` and `k3d-<name>-master-<i>`
Labels: make(map[string]string, 1),
Role: k3d.MasterRole,
Image: image,
Volumes: volumes, // add only volumes for `all`, `masters`, `master[i]` and `k3d-<name>-master-<i>`
MasterOpts: k3d.MasterOpts{},
}
if i == 0 {
node.Ports = append(node.Ports, fmt.Sprintf("0.0.0.0:%s:6443/tcp", apiPort)) // TODO: update (choose interface, enable more than one master) and get '6443' from defaultport variable
node.Labels["k3d.master.apiPort"] = apiPort
node.MasterOpts.ExposeAPI = exposeAPI
}
cluster.Nodes = append(cluster.Nodes, node)
}
@ -164,6 +165,7 @@ func parseCreateClusterCmd(cmd *cobra.Command, args []string) (runtimes.Runtime,
Volumes: volumes, // add only volumes for `all`, `workers`, `worker[i]` and `k3d-<name>-worker-<i>`
}
cluster.Nodes = append(cluster.Nodes, node)
}
return runtime, cluster

@ -71,7 +71,9 @@ func CreateCluster(cluster *k3d.Cluster, runtime k3drt.Runtime) error {
for _, node := range cluster.Nodes {
// cluster specific settings
node.Labels = make(map[string]string)
if node.Labels == nil {
node.Labels = make(map[string]string) // TODO: maybe create an init function?
}
node.Labels["k3d.cluster"] = cluster.Name
node.Env = append(node.Env, fmt.Sprintf("K3S_CLUSTER_SECRET=%s", cluster.Secret))

@ -23,8 +23,10 @@ package cluster
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/rancher/k3d/pkg/runtimes"
k3d "github.com/rancher/k3d/pkg/types"
@ -33,14 +35,41 @@ import (
// GetKubeconfig grabs the kubeconfig file from /output from a master node container and puts it into a local directory
func GetKubeconfig(runtime runtimes.Runtime, cluster *k3d.Cluster) ([]byte, error) {
// get all master nodes for the selected cluster
masterNodes, err := runtime.GetNodesByLabel(map[string]string{"k3d.cluster": cluster.Name, "k3d.role": string(k3d.MasterRole)})
if err != nil {
log.Errorln("Failed to get masternodes")
log.Errorln("Failed to get master nodes")
return nil, err
}
reader, err := runtime.GetKubeconfig(masterNodes[0])
if len(masterNodes) == 0 {
return nil, fmt.Errorf("Didn't find any master node")
}
// prefer a master node, which actually has the port exposed
var chosenMaster *k3d.Node
chosenMaster = nil
APIPort := "6443" // TODO: use default from types
APIHost := "localhost" // TODO: use default from types
for _, master := range masterNodes {
if _, ok := master.Labels["k3d.master.api.port"]; ok {
chosenMaster = master
APIPort = master.Labels["k3d.master.api.port"]
if _, ok := master.Labels["k3d.master.api.host"]; ok {
APIHost = master.Labels["k3d.master.api.host"]
}
break
}
}
if chosenMaster == nil {
chosenMaster = masterNodes[0]
}
// get the kubeconfig from the first master node
reader, err := runtime.GetKubeconfig(chosenMaster)
if err != nil {
log.Errorf("Failed to get kubeconfig from node '%s'", masterNodes[0].Name)
log.Errorf("Failed to get kubeconfig from node '%s'", chosenMaster)
return nil, err
}
defer reader.Close()
@ -51,10 +80,13 @@ func GetKubeconfig(runtime runtimes.Runtime, cluster *k3d.Cluster) ([]byte, erro
return nil, err
}
// write to file, skipping the first 512 bytes which contain file metadata
// and trimming any NULL characters
// drop the first 512 bytes which contain file metadata
// and trim any NULL characters
trimBytes := bytes.Trim(readBytes[512:], "\x00")
// replace host and port where the API is exposed with what we've found in the master node labels (or use the default)
trimBytes = []byte(strings.Replace(string(trimBytes), "localhost:6443", fmt.Sprintf("%s:%s", APIHost, APIPort), 1)) // replace localhost:6443 with localhost:<mappedAPIPort> in kubeconfig
return trimBytes, nil
}

@ -114,5 +114,26 @@ func patchWorkerSpec(node *k3d.Node) error {
func patchMasterSpec(node *k3d.Node) error {
node.Args = append([]string{"server"}, node.Args...)
node.Labels["k3d.role"] = string(k3d.MasterRole) // TODO: maybe put those in a global var DefaultMasterNodeSpec?
hostIP := "0.0.0.0" // TODO: from defaults
apiPort := "6443" // TODO: from defaults
if node.MasterOpts.ExposeAPI.Port != "" {
apiPort = node.MasterOpts.ExposeAPI.Port
node.Labels["k3d.master.api.port"] = node.MasterOpts.ExposeAPI.Port
if node.MasterOpts.ExposeAPI.Host != "" {
hostIP = node.MasterOpts.ExposeAPI.HostIP
node.Labels["k3d.master.api.hostIP"] = node.MasterOpts.ExposeAPI.HostIP // TODO: maybe get docker machine IP here
node.Labels["k3d.master.api.host"] = node.MasterOpts.ExposeAPI.Host
}
}
node.Ports = append(node.Ports, fmt.Sprintf("%s:%s:6443/tcp", hostIP, apiPort)) // TODO: get '6443' from defaultport variable
return nil
}

@ -0,0 +1,69 @@
/*
Copyright © 2019 Thorsten Klein <iwilltry42@gmail.com>
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 cluster
import (
"fmt"
"net"
"strconv"
"strings"
k3d "github.com/rancher/k3d/pkg/types"
log "github.com/sirupsen/logrus"
)
// ParseAPIPort parses/validates a string to create an exposeAPI struct from it
func ParseAPIPort(portString string) (k3d.ExposeAPI, error) {
var exposeAPI k3d.ExposeAPI
split := strings.Split(portString, ":")
if len(split) > 2 {
log.Errorln("Failed to parse API Port specification")
return exposeAPI, fmt.Errorf("api-port format error")
}
if len(split) == 1 {
exposeAPI = k3d.ExposeAPI{Port: split[0]}
} else {
// Make sure 'host' can be resolved to an IP address
addrs, err := net.LookupHost(split[0])
if err != nil {
return exposeAPI, err
}
exposeAPI = k3d.ExposeAPI{Host: split[0], HostIP: addrs[0], Port: split[1]}
}
// Verify 'port' is an integer and within port ranges
p, err := strconv.Atoi(exposeAPI.Port)
if err != nil {
return exposeAPI, err
}
if p < 0 || p > 65535 {
log.Errorln("Failed to parse API Port specification")
return exposeAPI, fmt.Errorf("port value '%d' out of range", p)
}
return exposeAPI, nil
}

@ -79,17 +79,35 @@ type Cluster struct {
// Node describes a k3d node
type Node struct {
Name string `yaml:"name" json:"name,omitempty"`
Role Role `yaml:"role" json:"role,omitempty"`
Image string `yaml:"image" json:"image,omitempty"`
Volumes []string `yaml:"volumes" json:"volumes,omitempty"`
Env []string `yaml:"env" json:"env,omitempty"`
Cmd []string // filled automatically based on role
Args []string `yaml:"extra_args" json:"extraArgs,omitempty"`
Ports []string `yaml:"port_mappings" json:"portMappings,omitempty"` // TODO: make a struct out of this?
Restart bool `yaml:"restart" json:"restart,omitempty"`
Labels map[string]string // filled automatically
Network string // filled automatically
Name string `yaml:"name" json:"name,omitempty"`
Role Role `yaml:"role" json:"role,omitempty"`
Image string `yaml:"image" json:"image,omitempty"`
Volumes []string `yaml:"volumes" json:"volumes,omitempty"`
Env []string `yaml:"env" json:"env,omitempty"`
Cmd []string // filled automatically based on role
Args []string `yaml:"extra_args" json:"extraArgs,omitempty"`
Ports []string `yaml:"port_mappings" json:"portMappings,omitempty"` // TODO: make a struct out of this?
Restart bool `yaml:"restart" json:"restart,omitempty"`
Labels map[string]string // filled automatically
Network string // filled automatically
MasterOpts MasterOpts `yaml:"master_opts" json:"masterOpts,omitempty"`
WorkerOpts WorkerOpts `yaml:"worker_opts" json:"workerOpts,omitempty"`
}
// MasterOpts describes some additional master role specific opts
type MasterOpts struct {
ExposeAPI ExposeAPI `yaml:"expose_api" json:"exposeAPI,omitempty"`
}
// ExposeAPI describes specs needed to expose the API-Server
type ExposeAPI struct {
Host string `yaml:"host" json:"host,omitempty"`
HostIP string `yaml:"host_ip" json:"hostIP,omitempty"`
Port string `yaml:"port" json:"port"`
}
// WorkerOpts describes some additional worker role specific opts
type WorkerOpts struct {
}
// GetDefaultObjectName prefixes the passed name with the default prefix

Loading…
Cancel
Save