forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node_args.go
255 lines (205 loc) · 8.38 KB
/
node_args.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package start
import (
"errors"
"fmt"
"net"
"net/url"
"os/exec"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/master/ports"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/sets"
"github.com/openshift/openshift-sdn/plugins/osdn/ovs"
"github.com/openshift/origin/pkg/cmd/server/admin"
configapi "github.com/openshift/origin/pkg/cmd/server/api"
configapiv1 "github.com/openshift/origin/pkg/cmd/server/api/v1"
cmdutil "github.com/openshift/origin/pkg/cmd/util"
utilflags "github.com/openshift/origin/pkg/cmd/util/flags"
)
const (
ComponentGroupNetwork = "network"
ComponentProxy = "proxy"
ComponentPlugins = "plugins"
ComponentKubelet = "kubelet"
)
// NewNodeComponentFlag returns a flag capable of handling enabled components for the node
func NewNodeComponentFlag() *utilflags.ComponentFlag {
return utilflags.NewComponentFlag(
map[string][]string{ComponentGroupNetwork: {ComponentProxy, ComponentPlugins}},
ComponentKubelet, ComponentProxy, ComponentPlugins,
)
}
// NewNodeComponentFlag returns a flag capable of handling enabled components for the network
func NewNetworkComponentFlag() *utilflags.ComponentFlag {
return utilflags.NewComponentFlag(nil, ComponentProxy, ComponentPlugins)
}
// NodeArgs is a struct that the command stores flag values into. It holds a partially complete set of parameters for starting a node.
// 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 {
// Components is the set of enabled components.
Components *utilflags.ComponentFlag
// NodeName is the hostname to identify this node with the master.
NodeName string
MasterCertDir string
ConfigDir util.StringFlag
AllowDisabledDocker bool
// VolumeDir is the volume storage directory.
VolumeDir string
DefaultKubernetesURL *url.URL
ClusterDomain string
ClusterDNS net.IP
// NetworkPluginName is the network plugin to be called for configuring networking for pods.
NetworkPluginName string
ListenArg *ListenArg
ImageFormatArgs *ImageFormatArgs
KubeConnectionArgs *KubeConnectionArgs
}
// BindNodeArgs binds the options to the flags with prefix + default flag names
func BindNodeArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string, components bool) {
if components {
args.Components.Bind(flags, prefix+"%s", "The set of node components to")
}
flags.StringVar(&args.NetworkPluginName, prefix+"network-plugin", args.NetworkPluginName, "The network plugin to be called for configuring networking for pods.")
flags.StringVar(&args.VolumeDir, prefix+"volume-dir", "openshift.local.volumes", "The volume storage directory.")
// TODO rename this node-name and recommend uname -n
flags.StringVar(&args.NodeName, prefix+"hostname", args.NodeName, "The hostname to identify this node with the master.")
// autocompletion hints
cobra.MarkFlagFilename(flags, prefix+"volume-dir")
}
// BindNodeNetworkArgs binds the options to the flags with prefix + default flag names
func BindNodeNetworkArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string) {
args.Components.Bind(flags, "%s", "The set of network components to")
flags.StringVar(&args.NetworkPluginName, prefix+"network-plugin", args.NetworkPluginName, "The network plugin to be called for configuring networking for pods.")
}
// NewDefaultNodeArgs creates NodeArgs with sub-objects created and default values set.
func NewDefaultNodeArgs() *NodeArgs {
hostname, err := defaultHostname()
if err != nil {
hostname = "localhost"
}
var dnsIP net.IP
if clusterDNS := cmdutil.Env("OPENSHIFT_DNS_ADDR", ""); len(clusterDNS) > 0 {
dnsIP = net.ParseIP(clusterDNS)
}
config := &NodeArgs{
Components: NewNodeComponentFlag(),
NodeName: hostname,
MasterCertDir: "openshift.local.config/master",
ClusterDomain: cmdutil.Env("OPENSHIFT_DNS_DOMAIN", "cluster.local"),
ClusterDNS: dnsIP,
NetworkPluginName: "",
ListenArg: NewDefaultListenArg(),
ImageFormatArgs: NewDefaultImageFormatArgs(),
KubeConnectionArgs: NewDefaultKubeConnectionArgs(),
}
config.ConfigDir.Default("openshift.local.config/node")
return config
}
func (args NodeArgs) Validate() error {
if err := args.KubeConnectionArgs.Validate(); err != nil {
return err
}
if _, err := args.KubeConnectionArgs.GetKubernetesAddress(args.DefaultKubernetesURL); err != nil {
return errors.New("--kubeconfig must be set to provide API server connection information")
}
return nil
}
func ValidateRuntime(config *configapi.NodeConfig, components *utilflags.ComponentFlag) error {
actual, err := components.Validate()
if err != nil {
return err
}
if actual.Len() == 0 {
return fmt.Errorf("at least one node component must be enabled (%s)", strings.Join(components.Allowed().List(), ", "))
}
switch strings.ToLower(config.NetworkConfig.NetworkPluginName) {
case ovs.MultiTenantPluginName():
if actual.Has(ComponentKubelet) && !actual.Has(ComponentPlugins) {
return fmt.Errorf("the multi-tenant SDN plugin must be run in the same process as the kubelet")
}
if actual.Has(ComponentProxy) && !actual.Has(ComponentPlugins) {
return fmt.Errorf("the multi-tenant SDN plugin requires the proxy and plugins components be enabled in the same process")
}
case ovs.SingleTenantPluginName():
if actual.Has(ComponentKubelet) && !actual.Has(ComponentPlugins) {
return fmt.Errorf("the SDN plugin must be run in the same process as the kubelet")
}
}
return nil
}
// 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)),
},
ImageConfig: configapi.ImageConfig{
Format: args.ImageFormatArgs.ImageTemplate.Format,
Latest: args.ImageFormatArgs.ImageTemplate.Latest,
},
NetworkConfig: configapi.NodeNetworkConfig{
NetworkPluginName: args.NetworkPluginName,
},
VolumeDirectory: args.VolumeDir,
AllowDisabledDocker: args.AllowDisabledDocker,
DNSDomain: args.ClusterDomain,
DNSIP: dnsIP,
MasterKubeConfig: admin.DefaultNodeKubeConfigFile(args.ConfigDir.Value()),
PodManifestConfig: nil,
}
if args.ListenArg.UseTLS() {
config.ServingInfo.ServerCert = admin.DefaultNodeServingCertInfo(args.ConfigDir.Value())
config.ServingInfo.ClientCA = admin.DefaultKubeletClientCAFile(args.MasterCertDir)
}
internal, err := applyDefaults(config, configapiv1.SchemeGroupVersion)
if err != nil {
return nil, err
}
return internal.(*configapi.NodeConfig), nil
}
// GetServerCertHostnames returns the set of hostnames and IP addresses a serving certificate for node on this host might need to be valid for.
func (args NodeArgs) GetServerCertHostnames() (sets.String, error) {
allHostnames := sets.NewString(args.NodeName)
listenIP := net.ParseIP(args.ListenArg.ListenAddr.Host)
// add the IPs that might be used based on the ListenAddr.
if listenIP != nil && listenIP.IsUnspecified() {
allAddresses, _ := cmdutil.AllLocalIP4()
for _, ip := range allAddresses {
allHostnames.Insert(ip.String())
}
} else {
allHostnames.Insert(args.ListenArg.ListenAddr.Host)
}
certHostnames := sets.String{}
for hostname := range allHostnames {
if host, _, err := net.SplitHostPort(hostname); err == nil {
// add the hostname without the port
certHostnames.Insert(host)
} else {
// add the originally specified hostname
certHostnames.Insert(hostname)
}
}
return certHostnames, nil
}
// 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("uname", "-n").Output()
if err != nil {
return "", fmt.Errorf("Couldn't determine hostname: %v", err)
}
return strings.ToLower(strings.TrimSpace(string(fqdn))), nil
}