package start
import (
"fmt"
"net"
"net/url"
"os/exec"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
"github.com/golang/glog"
"github.com/spf13/pflag"
"github.com/openshift/origin/pkg/cmd/server/admin"
configapi "github.com/openshift/origin/pkg/cmd/server/api"
latestconfigapi "github.com/openshift/origin/pkg/cmd/server/api/latest"
cmdutil "github.com/openshift/origin/pkg/cmd/util"
)
// NodeArgs is a struct that the command stores flag values into. It holds a partially complete set of parameters for starting the master
// This object should hold the common set values, but not attempt to handle all cases. The expected path is to use this object to create
// a fully specified config later on. If you need something not set here, then create a fully specified config file and pass that as argument
// to starting the master.
type NodeArgs struct {
NodeName string
AllowDisabledDocker bool
VolumeDir string
DefaultKubernetesURL url.URL
ClusterDomain string
ClusterDNS net.IP
ListenArg *ListenArg
ImageFormatArgs *ImageFormatArgs
KubeConnectionArgs *KubeConnectionArgs
CertArgs *CertArgs
}
// BindNodeArgs binds the options to the flags with prefix + default flag names
func BindNodeArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string) {
flags.StringVar(&args.VolumeDir, prefix+"volume-dir", "openshift.local.volumes", "The volume storage directory.")
// TODO rename this node-name and recommend hostname -f
flags.StringVar(&args.NodeName, prefix+"hostname", args.NodeName, "The hostname to identify this node with the master.")
}
// NewDefaultNodeArgs creates NodeArgs with sub-objects created and default values set.
func NewDefaultNodeArgs() *NodeArgs {
hostname, err := defaultHostname()
if err != nil {
hostname = "localhost"
glog.Warningf("Unable to lookup hostname, using %q: %v", hostname, err)
}
var dnsIP net.IP
if clusterDNS := cmdutil.Env("OPENSHIFT_DNS_ADDR", ""); len(clusterDNS) > 0 {
dnsIP = net.ParseIP(clusterDNS)
}
return &NodeArgs{
NodeName: hostname,
ClusterDomain: cmdutil.Env("OPENSHIFT_DNS_DOMAIN", "local"),
ClusterDNS: dnsIP,
ListenArg: NewDefaultListenArg(),
ImageFormatArgs: NewDefaultImageFormatArgs(),
KubeConnectionArgs: NewDefaultKubeConnectionArgs(),
CertArgs: NewDefaultCertArgs(),
}
}
// BuildSerializeableNodeConfig takes the NodeArgs (partially complete config) and uses them along with defaulting behavior to create the fully specified
// config object for starting the node
func (args NodeArgs) BuildSerializeableNodeConfig() (*configapi.NodeConfig, error) {
var dnsIP string
if len(args.ClusterDNS) > 0 {
dnsIP = args.ClusterDNS.String()
}
config := &configapi.NodeConfig{
NodeName: args.NodeName,
ServingInfo: configapi.ServingInfo{
BindAddress: net.JoinHostPort(args.ListenArg.ListenAddr.Host, strconv.Itoa(ports.KubeletPort)),
},
VolumeDirectory: args.VolumeDir,
NetworkContainerImage: args.ImageFormatArgs.ImageTemplate.ExpandOrDie("pod"),
AllowDisabledDocker: args.AllowDisabledDocker,
DNSDomain: args.ClusterDomain,
DNSIP: dnsIP,
MasterKubeConfig: admin.DefaultNodeKubeConfigFile(args.CertArgs.CertDir, args.NodeName),
}
if args.ListenArg.UseTLS() {
config.ServingInfo.ServerCert = admin.DefaultNodeServingCertInfo(args.CertArgs.CertDir, args.NodeName)
}
return config, nil
}
// WriteNode serializes the config to yaml.
func WriteNode(config *configapi.NodeConfig) ([]byte, error) {
json, err := latestconfigapi.Codec.Encode(config)
if err != nil {
return nil, err
}
return json, err
}
// defaultHostname returns the default hostname for this system.
func defaultHostname() (string, error) {
// Note: We use exec here instead of os.Hostname() because we
// want the FQDN, and this is the easiest way to get it.
fqdn, err := exec.Command("hostname", "-f").Output()
if err != nil {
return "", fmt.Errorf("Couldn't determine hostname: %v", err)
}
return strings.TrimSpace(string(fqdn)), nil
}