... | ... |
@@ -75,7 +75,7 @@ OPENSHIFT_ON_PANIC=crash openshift start --master="${API_SCHEME}://${API_HOST}:$ |
75 | 75 |
OS_PID=$! |
76 | 76 |
|
77 | 77 |
if [[ "${API_SCHEME}" == "https" ]]; then |
78 |
- export CURL_CA_BUNDLE="${CERT_DIR}/admin/root.crt" |
|
78 |
+ export CURL_CA_BUNDLE="${CERT_DIR}/ca/cert.crt" |
|
79 | 79 |
export CURL_CERT="${CERT_DIR}/admin/cert.crt" |
80 | 80 |
export CURL_KEY="${CERT_DIR}/admin/key.key" |
81 | 81 |
fi |
... | ... |
@@ -174,14 +174,18 @@ echo "templates: ok" |
174 | 174 |
[ "$(osc get --help 2>&1 | grep 'Display one or many resources')" ] |
175 | 175 |
[ "$(openshift cli get --help 2>&1 | grep 'Display one or many resources')" ] |
176 | 176 |
[ "$(openshift kubectl get --help 2>&1 | grep 'Display one or many resources')" ] |
177 |
-[ "$(openshift start --help 2>&1 | grep 'Start an OpenShift server')" ] |
|
177 |
+[ "$(openshift start --help 2>&1 | grep 'Start an OpenShift all-in-one server')" ] |
|
178 |
+[ "$(openshift start master --help 2>&1 | grep 'Start an OpenShift master')" ] |
|
179 |
+[ "$(openshift start node --help 2>&1 | grep 'Start an OpenShift node')" ] |
|
178 | 180 |
[ "$(osc get --help 2>&1 | grep 'osc')" ] |
179 | 181 |
|
180 | 182 |
# help for given command through help command must be consistent |
181 | 183 |
[ "$(osc help get 2>&1 | grep 'Display one or many resources')" ] |
182 | 184 |
[ "$(openshift cli help get 2>&1 | grep 'Display one or many resources')" ] |
183 | 185 |
[ "$(openshift kubectl help get 2>&1 | grep 'Display one or many resources')" ] |
184 |
-[ "$(openshift help start 2>&1 | grep 'Start an OpenShift server')" ] |
|
186 |
+[ "$(openshift help start 2>&1 | grep 'Start an OpenShift all-in-one server')" ] |
|
187 |
+[ "$(openshift help start master 2>&1 | grep 'Start an OpenShift master')" ] |
|
188 |
+[ "$(openshift help start node 2>&1 | grep 'Start an OpenShift node')" ] |
|
185 | 189 |
[ "$(openshift cli help update 2>&1 | grep 'openshift')" ] |
186 | 190 |
|
187 | 191 |
# runnable commands with required flags must error consistently |
... | ... |
@@ -50,9 +50,12 @@ LOG_DIR="${LOG_DIR:-${BASETMPDIR}/logs}" |
50 | 50 |
ARTIFACT_DIR="${ARTIFACT_DIR:-${BASETMPDIR}/artifacts}" |
51 | 51 |
mkdir -p $LOG_DIR |
52 | 52 |
mkdir -p $ARTIFACT_DIR |
53 |
+ |
|
54 |
+DEFAULT_SERVER_IP=`ifconfig | grep -Ev "(127.0.0.1|172.17.42.1)" | grep "inet " | head -n 1 | awk '{print $2}'` |
|
55 |
+API_HOST="${API_HOST:-${DEFAULT_SERVER_IP}}" |
|
53 | 56 |
API_PORT="${API_PORT:-8443}" |
54 | 57 |
API_SCHEME="${API_SCHEME:-https}" |
55 |
-API_HOST="${API_HOST:-localhost}" |
|
58 |
+MASTER_ADDR="${API_SCHEME}://${API_HOST}:${API_PORT}" |
|
56 | 59 |
PUBLIC_MASTER_HOST="${PUBLIC_MASTER_HOST:-${API_HOST}}" |
57 | 60 |
KUBELET_SCHEME="${KUBELET_SCHEME:-http}" |
58 | 61 |
KUBELET_PORT="${KUBELET_PORT:-10250}" |
... | ... |
@@ -168,25 +171,32 @@ echo "[INFO] Using images: ${USE_IMAGES}" |
168 | 168 |
|
169 | 169 |
# Start All-in-one server and wait for health |
170 | 170 |
# Specify the scheme and port for the listen address, but let the IP auto-discover. Set --public-master to localhost, for a stable link to the console. |
171 |
+echo "[INFO] Create certificates for the OpenShift server" |
|
172 |
+# find the same IP that openshift start will bind to. This allows access from pods that have to talk back to master |
|
173 |
+ALL_IP_ADDRESSES=`ifconfig | grep "inet " | awk '{print $2}'` |
|
174 |
+SERVER_HOSTNAME_LIST="${PUBLIC_MASTER_HOST},localhost" |
|
175 |
+while read -r IP_ADDRESS |
|
176 |
+do |
|
177 |
+ SERVER_HOSTNAME_LIST="${SERVER_HOSTNAME_LIST},${IP_ADDRESS}" |
|
178 |
+done <<< "${ALL_IP_ADDRESSES}" |
|
179 |
+ |
|
180 |
+openshift admin create-all-certs --overwrite=false --cert-dir="${CERT_DIR}" --hostnames="${SERVER_HOSTNAME_LIST}" --nodes="127.0.0.1" --master="${MASTER_ADDR}" --public-master="${API_SCHEME}://${PUBLIC_MASTER_HOST}" |
|
181 |
+ |
|
182 |
+ |
|
171 | 183 |
echo "[INFO] Starting OpenShift server" |
172 | 184 |
sudo env "PATH=${PATH}" OPENSHIFT_ON_PANIC=crash openshift start \ |
173 |
- --listen="${API_SCHEME}://0.0.0.0:${API_PORT}" --public-master="${API_SCHEME}://${PUBLIC_MASTER_HOST}" \ |
|
185 |
+ --listen="${API_SCHEME}://0.0.0.0:${API_PORT}" --master="${MASTER_ADDR}" --public-master="${API_SCHEME}://${PUBLIC_MASTER_HOST}" \ |
|
174 | 186 |
--hostname="127.0.0.1" --volume-dir="${VOLUME_DIR}" \ |
175 | 187 |
--etcd-dir="${ETCD_DATA_DIR}" --cert-dir="${CERT_DIR}" --loglevel=4 \ |
176 |
- --images="${USE_IMAGES}" \ |
|
188 |
+ --images="${USE_IMAGES}" --create-certs=false\ |
|
177 | 189 |
&> "${LOG_DIR}/openshift.log" & |
178 | 190 |
OS_PID=$! |
179 | 191 |
|
180 | 192 |
if [[ "${API_SCHEME}" == "https" ]]; then |
181 |
- export CURL_CA_BUNDLE="${CERT_DIR}/master/root.crt" |
|
193 |
+ export CURL_CA_BUNDLE="${CERT_DIR}/ca/cert.crt" |
|
182 | 194 |
export CURL_CERT="${CERT_DIR}/admin/cert.crt" |
183 | 195 |
export CURL_KEY="${CERT_DIR}/admin/key.key" |
184 | 196 |
|
185 |
- # Generate the certs first |
|
186 |
- wait_for_file "${CERT_DIR}/openshift-client/key.key" 0.5 80 |
|
187 |
- wait_for_file "${CERT_DIR}/admin/key.key" 0.5 80 |
|
188 |
- wait_for_file "${CURL_CA_BUNDLE}" 0.5 80 |
|
189 |
- |
|
190 | 197 |
# Read client cert data in to send to containerized components |
191 | 198 |
sudo chmod -R a+rX "${CERT_DIR}/openshift-client/" |
192 | 199 |
|
... | ... |
@@ -204,6 +214,9 @@ wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/api/v1beta1/minions/127.0. |
204 | 204 |
# Set KUBERNETES_MASTER for osc |
205 | 205 |
export KUBERNETES_MASTER="${API_SCHEME}://${API_HOST}:${API_PORT}" |
206 | 206 |
|
207 |
+# add e2e-user as a viewer for the default namespace so we can see infrastructure pieces appear |
|
208 |
+openshift ex policy add-user view anypassword:e2e-user --namespace=default |
|
209 |
+ |
|
207 | 210 |
# create test project so that this shows up in the console |
208 | 211 |
openshift ex new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="anypassword:e2e-user" |
209 | 212 |
|
... | ... |
@@ -44,12 +44,23 @@ start_etcd |
44 | 44 |
trap cleanup EXIT SIGINT |
45 | 45 |
|
46 | 46 |
function exectest() { |
47 |
+ echo "running $1..." |
|
48 |
+ |
|
47 | 49 |
out=$("${testexec}" -test.run="^$1$" "${@:2}" 2>&1) |
50 |
+ |
|
51 |
+ tput cuu 1 # Move up one line |
|
52 |
+ tput el # Clear "running" line |
|
53 |
+ |
|
48 | 54 |
res=$? |
49 | 55 |
if [[ ${res} -eq 0 ]]; then |
50 |
- echo ok $1 |
|
56 |
+ tput setaf 2 # green |
|
57 |
+ echo "ok $1" |
|
58 |
+ tput sgr0 # reset |
|
51 | 59 |
exit 0 |
52 | 60 |
else |
61 |
+ tput setaf 1 # red |
|
62 |
+ echo "failed $1" |
|
63 |
+ tput sgr0 # reset |
|
53 | 64 |
echo "${out}" |
54 | 65 |
exit 1 |
55 | 66 |
fi |
... | ... |
@@ -33,7 +33,7 @@ func TestSubjects(t *testing.T) { |
33 | 33 |
Resource: "pods", |
34 | 34 |
}, |
35 | 35 |
expectedUsers: util.NewStringSet("Anna", "ClusterAdmin", "Ellen", "Valerie", "system:kube-client", "system:openshift-client", "system:openshift-deployer"), |
36 |
- expectedGroups: util.NewStringSet("RootUsers", "system:cluster-admins"), |
|
36 |
+ expectedGroups: util.NewStringSet("RootUsers", "system:cluster-admins", "system:nodes"), |
|
37 | 37 |
} |
38 | 38 |
test.policies = newDefaultGlobalPolicies() |
39 | 39 |
test.policies = append(test.policies, newAdzePolicies()...) |
... | ... |
@@ -18,7 +18,8 @@ import ( |
18 | 18 |
"github.com/openshift/origin/pkg/cmd/infra/builder" |
19 | 19 |
"github.com/openshift/origin/pkg/cmd/infra/deployer" |
20 | 20 |
"github.com/openshift/origin/pkg/cmd/infra/router" |
21 |
- "github.com/openshift/origin/pkg/cmd/server" |
|
21 |
+ "github.com/openshift/origin/pkg/cmd/server/certs" |
|
22 |
+ "github.com/openshift/origin/pkg/cmd/server/start" |
|
22 | 23 |
"github.com/openshift/origin/pkg/cmd/templates" |
23 | 24 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
24 | 25 |
"github.com/openshift/origin/pkg/version" |
... | ... |
@@ -78,8 +79,9 @@ func NewCommandOpenShift() *cobra.Command { |
78 | 78 |
root.SetUsageTemplate(templates.MainUsageTemplate()) |
79 | 79 |
root.SetHelpTemplate(templates.MainHelpTemplate()) |
80 | 80 |
|
81 |
- openshiftStartCommand, _ := server.NewCommandStartServer("start") |
|
82 |
- root.AddCommand(openshiftStartCommand) |
|
81 |
+ startAllInOne, _ := start.NewCommandStartAllInOne() |
|
82 |
+ root.AddCommand(startAllInOne) |
|
83 |
+ root.AddCommand(certs.NewCommandAdmin()) |
|
83 | 84 |
root.AddCommand(cli.NewCommandCLI("cli", "openshift cli")) |
84 | 85 |
root.AddCommand(cli.NewCmdKubectl("kube")) |
85 | 86 |
root.AddCommand(newExperimentalCommand("openshift", "ex")) |
86 | 87 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,125 @@ |
0 |
+package api |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "crypto/x509" |
|
4 |
+ "fmt" |
|
5 |
+ "io/ioutil" |
|
6 |
+ |
|
7 |
+ kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
8 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
9 |
+ |
|
10 |
+ "github.com/openshift/origin/pkg/client" |
|
11 |
+ "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+func GetKubeClient(kubeConfigFile string) (*kclient.Client, *kclient.Config, error) { |
|
15 |
+ loadingRules := &clientcmd.ClientConfigLoadingRules{CommandLinePath: kubeConfigFile} |
|
16 |
+ loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) |
|
17 |
+ |
|
18 |
+ kubeConfig, err := loader.ClientConfig() |
|
19 |
+ if err != nil { |
|
20 |
+ return nil, nil, err |
|
21 |
+ } |
|
22 |
+ kubeClient, err := kclient.New(kubeConfig) |
|
23 |
+ if err != nil { |
|
24 |
+ return nil, nil, err |
|
25 |
+ } |
|
26 |
+ |
|
27 |
+ return kubeClient, kubeConfig, nil |
|
28 |
+} |
|
29 |
+ |
|
30 |
+func GetOpenShiftClient(kubeConfigFile string) (*client.Client, *kclient.Config, error) { |
|
31 |
+ loadingRules := &clientcmd.ClientConfigLoadingRules{CommandLinePath: kubeConfigFile} |
|
32 |
+ loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) |
|
33 |
+ |
|
34 |
+ kubeConfig, err := loader.ClientConfig() |
|
35 |
+ if err != nil { |
|
36 |
+ return nil, nil, err |
|
37 |
+ } |
|
38 |
+ openshiftClient, err := client.New(kubeConfig) |
|
39 |
+ if err != nil { |
|
40 |
+ return nil, nil, err |
|
41 |
+ } |
|
42 |
+ |
|
43 |
+ return openshiftClient, kubeConfig, nil |
|
44 |
+} |
|
45 |
+ |
|
46 |
+func UseTLS(servingInfo ServingInfo) bool { |
|
47 |
+ return len(servingInfo.ServerCert.CertFile) > 0 |
|
48 |
+} |
|
49 |
+ |
|
50 |
+// GetAPIClientCertCAPool returns the cert pool used to validate client certificates to the API server |
|
51 |
+func GetAPIClientCertCAPool(options MasterConfig) (*x509.CertPool, error) { |
|
52 |
+ certs, err := getAPIClientCertCAs(options) |
|
53 |
+ if err != nil { |
|
54 |
+ return nil, err |
|
55 |
+ } |
|
56 |
+ roots := x509.NewCertPool() |
|
57 |
+ for _, root := range certs { |
|
58 |
+ roots.AddCert(root) |
|
59 |
+ } |
|
60 |
+ return roots, nil |
|
61 |
+} |
|
62 |
+ |
|
63 |
+// GetClientCertCAPool returns a cert pool containing all client CAs that could be presented (union of API and OAuth) |
|
64 |
+func GetClientCertCAPool(options MasterConfig) (*x509.CertPool, error) { |
|
65 |
+ roots := x509.NewCertPool() |
|
66 |
+ |
|
67 |
+ // Add CAs for OAuth |
|
68 |
+ certs, err := getOAuthClientCertCAs(options) |
|
69 |
+ if err != nil { |
|
70 |
+ return nil, err |
|
71 |
+ } |
|
72 |
+ for _, root := range certs { |
|
73 |
+ roots.AddCert(root) |
|
74 |
+ } |
|
75 |
+ |
|
76 |
+ // Add CAs for API |
|
77 |
+ certs, err = getAPIClientCertCAs(options) |
|
78 |
+ if err != nil { |
|
79 |
+ return nil, err |
|
80 |
+ } |
|
81 |
+ for _, root := range certs { |
|
82 |
+ roots.AddCert(root) |
|
83 |
+ } |
|
84 |
+ |
|
85 |
+ return roots, nil |
|
86 |
+} |
|
87 |
+ |
|
88 |
+// GetAPIServerCertCAPool returns the cert pool containing the roots for the API server cert |
|
89 |
+func GetAPIServerCertCAPool(options MasterConfig) (*x509.CertPool, error) { |
|
90 |
+ caRoots, err := crypto.GetTLSCARoots(options.ServingInfo.ClientCA) |
|
91 |
+ if err != nil { |
|
92 |
+ return nil, err |
|
93 |
+ } |
|
94 |
+ roots := x509.NewCertPool() |
|
95 |
+ for _, root := range caRoots.Roots { |
|
96 |
+ roots.AddCert(root) |
|
97 |
+ } |
|
98 |
+ return roots, nil |
|
99 |
+} |
|
100 |
+ |
|
101 |
+func getOAuthClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) { |
|
102 |
+ caFile := options.OAuthConfig.ProxyCA |
|
103 |
+ if len(caFile) == 0 { |
|
104 |
+ return nil, nil |
|
105 |
+ } |
|
106 |
+ caPEMBlock, err := ioutil.ReadFile(caFile) |
|
107 |
+ if err != nil { |
|
108 |
+ return nil, err |
|
109 |
+ } |
|
110 |
+ certs, err := crypto.CertsFromPEM(caPEMBlock) |
|
111 |
+ if err != nil { |
|
112 |
+ return nil, fmt.Errorf("Error reading %s: %s", caFile, err) |
|
113 |
+ } |
|
114 |
+ return certs, nil |
|
115 |
+} |
|
116 |
+ |
|
117 |
+func getAPIClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) { |
|
118 |
+ apiClientCertCAs, err := crypto.GetTLSCARoots(options.ServingInfo.ClientCA) |
|
119 |
+ if err != nil { |
|
120 |
+ return nil, err |
|
121 |
+ } |
|
122 |
+ |
|
123 |
+ return apiClientCertCAs.Roots, nil |
|
124 |
+} |
0 | 125 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,24 @@ |
0 |
+package latest |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/openshift/origin/pkg/cmd/server/api/v1" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+// Version is the string that represents the current external default version. |
|
7 |
+const Version = "v1" |
|
8 |
+ |
|
9 |
+// OldestVersion is the string that represents the oldest server version supported, |
|
10 |
+// for client code that wants to hardcode the lowest common denominator. |
|
11 |
+const OldestVersion = "v1" |
|
12 |
+ |
|
13 |
+// Versions is the list of versions that are recognized in code. The order provided |
|
14 |
+// may be assumed to be least feature rich to most feature rich, and clients may |
|
15 |
+// choose to prefer the latter items in the list over the former items when presented |
|
16 |
+// with a set of versions to choose. |
|
17 |
+var Versions = []string{"v1"} |
|
18 |
+ |
|
19 |
+// Codec is the default codec for serializing output that should use |
|
20 |
+// the latest supported version. Use this Codec when writing to |
|
21 |
+// disk, a data store that is not dynamically versioned, or in tests. |
|
22 |
+// This codec can decode any object that Kubernetes is aware of. |
|
23 |
+var Codec = v1.Codec |
0 | 24 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,17 @@ |
0 |
+package api |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+var Scheme = runtime.NewScheme() |
|
7 |
+ |
|
8 |
+func init() { |
|
9 |
+ Scheme.AddKnownTypes("", |
|
10 |
+ &MasterConfig{}, |
|
11 |
+ &NodeConfig{}, |
|
12 |
+ ) |
|
13 |
+} |
|
14 |
+ |
|
15 |
+func (*MasterConfig) IsAnAPIObject() {} |
|
16 |
+func (*NodeConfig) IsAnAPIObject() {} |
0 | 17 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,161 @@ |
0 |
+package api |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+// NodeConfig is the fully specified config starting an OpenShift node |
|
7 |
+type NodeConfig struct { |
|
8 |
+ api.TypeMeta |
|
9 |
+ |
|
10 |
+ // NodeName is the value used to identify this particular node in the cluster. If possible, this should be your fully qualified hostname. |
|
11 |
+ // If you're describing a set of static nodes to the master, this value must match one of the values in the list |
|
12 |
+ NodeName string |
|
13 |
+ |
|
14 |
+ // ServingInfo describes how to start serving |
|
15 |
+ ServingInfo ServingInfo |
|
16 |
+ |
|
17 |
+ // MasterKubeConfig is a filename for the .kubeconfig file that describes how to connect this node to the master |
|
18 |
+ MasterKubeConfig string |
|
19 |
+ |
|
20 |
+ // domain suffix |
|
21 |
+ DNSDomain string |
|
22 |
+ // ip |
|
23 |
+ DNSIP string |
|
24 |
+ |
|
25 |
+ // VolumeDir is the directory that volumes will be stored under |
|
26 |
+ VolumeDirectory string |
|
27 |
+ |
|
28 |
+ // NetworkContainerImage is the image used as the Kubelet network namespace and volume container. |
|
29 |
+ NetworkContainerImage string |
|
30 |
+ |
|
31 |
+ // AllowDisabledDocker if true, the Kubelet will ignore errors from Docker. This means that a node can start on a machine that doesn't have docker started. |
|
32 |
+ AllowDisabledDocker bool |
|
33 |
+ |
|
34 |
+ // RecordEvents indicates whether or not to record events from the master |
|
35 |
+ RecordEvents bool |
|
36 |
+} |
|
37 |
+ |
|
38 |
+type MasterConfig struct { |
|
39 |
+ api.TypeMeta |
|
40 |
+ |
|
41 |
+ // ServingInfo describes how to start serving |
|
42 |
+ ServingInfo ServingInfo |
|
43 |
+ |
|
44 |
+ // CORSAllowedOrigins |
|
45 |
+ CORSAllowedOrigins []string |
|
46 |
+ |
|
47 |
+ // EtcdClientInfo contains information about how to connect to etcd |
|
48 |
+ EtcdClientInfo RemoteConnectionInfo |
|
49 |
+ |
|
50 |
+ // KubernetesMasterConfig, if present start the kubernetes master in this process |
|
51 |
+ KubernetesMasterConfig *KubernetesMasterConfig |
|
52 |
+ // EtcdConfig, if present start etcd in this process |
|
53 |
+ EtcdConfig *EtcdConfig |
|
54 |
+ // OAuthConfig, if present start the /oauth endpoint in this process |
|
55 |
+ OAuthConfig *OAuthConfig |
|
56 |
+ // AssetConfig, if present start the asset serverin this process |
|
57 |
+ AssetConfig *AssetConfig |
|
58 |
+ // DNSConfig, if present start the DNS server in this process |
|
59 |
+ DNSConfig *DNSConfig |
|
60 |
+ |
|
61 |
+ // MasterClients holds all the client connection information for controllers and other system components |
|
62 |
+ MasterClients MasterClients |
|
63 |
+ |
|
64 |
+ ImageConfig ImageConfig |
|
65 |
+ |
|
66 |
+ // MasterAuthorizationNamespace is the global namespace for Policy |
|
67 |
+ MasterAuthorizationNamespace string |
|
68 |
+ // OpenShiftSharedResourcesNamespace is the namespace where shared OpenShift resources live (like shared templates) |
|
69 |
+ OpenShiftSharedResourcesNamespace string |
|
70 |
+} |
|
71 |
+ |
|
72 |
+type ImageConfig struct { |
|
73 |
+ Format string |
|
74 |
+ Latest bool |
|
75 |
+} |
|
76 |
+ |
|
77 |
+type RemoteConnectionInfo struct { |
|
78 |
+ // URL is the URL for etcd |
|
79 |
+ URL string |
|
80 |
+ // CA is the CA for confirming that the server at the etcdURL is the actual server |
|
81 |
+ CA string |
|
82 |
+ // EtcdClientCertInfo is the TLS client cert information for securing communication to etcd |
|
83 |
+ // this is anonymous so that we can inline it for serialization |
|
84 |
+ ClientCert CertInfo |
|
85 |
+} |
|
86 |
+ |
|
87 |
+type ServingInfo struct { |
|
88 |
+ // BindAddress is the ip:port to serve on |
|
89 |
+ BindAddress string |
|
90 |
+ // ServerCert is the TLS cert info for serving secure traffic |
|
91 |
+ ServerCert CertInfo |
|
92 |
+ // ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates |
|
93 |
+ ClientCA string |
|
94 |
+} |
|
95 |
+ |
|
96 |
+type MasterClients struct { |
|
97 |
+ // DeployerKubeConfig is a .kubeconfig filename for depoyment pods to use |
|
98 |
+ DeployerKubeConfig string |
|
99 |
+ // OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master |
|
100 |
+ OpenShiftLoopbackKubeConfig string |
|
101 |
+ // KubernetesKubeConfig is a .kubeconfig filename for system components to communicate to kubernetes for building the proxy |
|
102 |
+ KubernetesKubeConfig string |
|
103 |
+} |
|
104 |
+ |
|
105 |
+type DNSConfig struct { |
|
106 |
+ // BindAddress is the ip:port to serve DNS on |
|
107 |
+ BindAddress string |
|
108 |
+} |
|
109 |
+ |
|
110 |
+type AssetConfig struct { |
|
111 |
+ ServingInfo ServingInfo |
|
112 |
+ |
|
113 |
+ // PublicURL is where you can find the asset server (TODO do we really need this?) |
|
114 |
+ PublicURL string |
|
115 |
+ |
|
116 |
+ // LogoutURI is an optional, absolute URI to redirect web browsers to after logging out of the web console. |
|
117 |
+ // If not specified, the built-in logout page is shown. |
|
118 |
+ LogoutURI string |
|
119 |
+ |
|
120 |
+ // MasterPublicURL is how the web console can access the OpenShift api server |
|
121 |
+ MasterPublicURL string |
|
122 |
+ |
|
123 |
+ // TODO: we probably don't need this since we have a proxy |
|
124 |
+ // KubernetesPublicURL is how the web console can access the Kubernetes api server |
|
125 |
+ KubernetesPublicURL string |
|
126 |
+} |
|
127 |
+ |
|
128 |
+type OAuthConfig struct { |
|
129 |
+ // ProxyCA is the certificate bundle for confirming the identity of front proxy forwards to the oauth server |
|
130 |
+ ProxyCA string |
|
131 |
+ |
|
132 |
+ // MasterURL is used for building valid client redirect URLs for external access |
|
133 |
+ MasterURL string |
|
134 |
+ |
|
135 |
+ // MasterPublicURL is used for building valid client redirect URLs for external access |
|
136 |
+ MasterPublicURL string |
|
137 |
+ |
|
138 |
+ // AssetPublicURL is used for building valid client redirect URLs for external access |
|
139 |
+ AssetPublicURL string |
|
140 |
+ |
|
141 |
+ // all the handlers here |
|
142 |
+} |
|
143 |
+ |
|
144 |
+type EtcdConfig struct { |
|
145 |
+ ServingInfo ServingInfo |
|
146 |
+ |
|
147 |
+ PeerAddress string |
|
148 |
+ MasterAddress string |
|
149 |
+ StorageDir string |
|
150 |
+} |
|
151 |
+ |
|
152 |
+type KubernetesMasterConfig struct { |
|
153 |
+ ServicesSubnet string |
|
154 |
+ StaticNodeNames []string |
|
155 |
+} |
|
156 |
+ |
|
157 |
+type CertInfo struct { |
|
158 |
+ CertFile string |
|
159 |
+ KeyFile string |
|
160 |
+} |
0 | 161 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,43 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/conversion" |
|
4 |
+ newer "github.com/openshift/origin/pkg/cmd/server/api" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+func init() { |
|
8 |
+ err := newer.Scheme.AddConversionFuncs( |
|
9 |
+ func(in *ServingInfo, out *newer.ServingInfo, s conversion.Scope) error { |
|
10 |
+ out.BindAddress = in.BindAddress |
|
11 |
+ out.ClientCA = in.ClientCA |
|
12 |
+ out.ServerCert.CertFile = in.CertFile |
|
13 |
+ out.ServerCert.KeyFile = in.KeyFile |
|
14 |
+ return nil |
|
15 |
+ }, |
|
16 |
+ func(in *newer.ServingInfo, out *ServingInfo, s conversion.Scope) error { |
|
17 |
+ out.BindAddress = in.BindAddress |
|
18 |
+ out.ClientCA = in.ClientCA |
|
19 |
+ out.CertFile = in.ServerCert.CertFile |
|
20 |
+ out.KeyFile = in.ServerCert.KeyFile |
|
21 |
+ return nil |
|
22 |
+ }, |
|
23 |
+ func(in *RemoteConnectionInfo, out *newer.RemoteConnectionInfo, s conversion.Scope) error { |
|
24 |
+ out.URL = in.URL |
|
25 |
+ out.CA = in.CA |
|
26 |
+ out.ClientCert.CertFile = in.CertFile |
|
27 |
+ out.ClientCert.KeyFile = in.KeyFile |
|
28 |
+ return nil |
|
29 |
+ }, |
|
30 |
+ func(in *newer.RemoteConnectionInfo, out *RemoteConnectionInfo, s conversion.Scope) error { |
|
31 |
+ out.URL = in.URL |
|
32 |
+ out.CA = in.CA |
|
33 |
+ out.CertFile = in.ClientCert.CertFile |
|
34 |
+ out.KeyFile = in.ClientCert.KeyFile |
|
35 |
+ return nil |
|
36 |
+ }, |
|
37 |
+ ) |
|
38 |
+ if err != nil { |
|
39 |
+ // If one of the conversion functions is malformed, detect it immediately. |
|
40 |
+ panic(err) |
|
41 |
+ } |
|
42 |
+} |
0 | 43 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,18 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" |
|
4 |
+ "github.com/openshift/origin/pkg/cmd/server/api" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+var Codec = runtime.CodecFor(api.Scheme, "v1") |
|
8 |
+ |
|
9 |
+func init() { |
|
10 |
+ api.Scheme.AddKnownTypes("v1", |
|
11 |
+ &MasterConfig{}, |
|
12 |
+ &NodeConfig{}, |
|
13 |
+ ) |
|
14 |
+} |
|
15 |
+ |
|
16 |
+func (*MasterConfig) IsAnAPIObject() {} |
|
17 |
+func (*NodeConfig) IsAnAPIObject() {} |
0 | 18 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,162 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+// NodeConfig is the fully specified config starting an OpenShift node |
|
7 |
+type NodeConfig struct { |
|
8 |
+ v1beta3.TypeMeta `json:",inline"` |
|
9 |
+ |
|
10 |
+ // NodeName is the value used to identify this particular node in the cluster. If possible, this should be your fully qualified hostname. |
|
11 |
+ // If you're describing a set of static nodes to the master, this value must match one of the values in the list |
|
12 |
+ NodeName string `json:"nodeName"` |
|
13 |
+ |
|
14 |
+ // ServingInfo describes how to start serving |
|
15 |
+ ServingInfo ServingInfo `json:"servingInfo"` |
|
16 |
+ |
|
17 |
+ // MasterKubeConfig is a filename for the .kubeconfig file that describes how to connect this node to the master |
|
18 |
+ MasterKubeConfig string `json:"masterKubeConfig"` |
|
19 |
+ |
|
20 |
+ // domain suffix |
|
21 |
+ DNSDomain string `json:"dnsDomain"` |
|
22 |
+ // ip |
|
23 |
+ DNSIP string `json:"dnsIP"` |
|
24 |
+ |
|
25 |
+ // VolumeDir is the directory that volumes will be stored under |
|
26 |
+ VolumeDirectory string `json:"volumeDirectory"` |
|
27 |
+ |
|
28 |
+ // NetworkContainerImage is the image used as the Kubelet network namespace and volume container. |
|
29 |
+ NetworkContainerImage string `json:"networkContainerImage"` |
|
30 |
+ |
|
31 |
+ // AllowDisabledDocker if true, the Kubelet will ignore errors from Docker. This means that a node can start on a machine that doesn't have docker started. |
|
32 |
+ AllowDisabledDocker bool `json:"allowDisabledDocker"` |
|
33 |
+ |
|
34 |
+ // RecordEvents indicates whether or not to record events from the master |
|
35 |
+ RecordEvents bool `json:"recordEvents"` |
|
36 |
+} |
|
37 |
+ |
|
38 |
+type MasterConfig struct { |
|
39 |
+ v1beta3.TypeMeta `json:",inline"` |
|
40 |
+ |
|
41 |
+ // ServingInfo describes how to start serving |
|
42 |
+ ServingInfo ServingInfo `json:"servingInfo"` |
|
43 |
+ |
|
44 |
+ // CORSAllowedOrigins |
|
45 |
+ CORSAllowedOrigins []string `json:"corsAllowedOrigins"` |
|
46 |
+ |
|
47 |
+ // EtcdClientInfo contains information about how to connect to etcd |
|
48 |
+ EtcdClientInfo RemoteConnectionInfo `json:"etcdClientInfo"` |
|
49 |
+ |
|
50 |
+ // KubernetesMasterConfig, if present start the kubernetes master in this process |
|
51 |
+ KubernetesMasterConfig *KubernetesMasterConfig `json:"kubernetesMasterConfig"` |
|
52 |
+ // EtcdConfig, if present start etcd in this process |
|
53 |
+ EtcdConfig *EtcdConfig `json:"etcdConfig"` |
|
54 |
+ // OAuthConfig, if present start the /oauth endpoint in this process |
|
55 |
+ OAuthConfig *OAuthConfig `json:"oauthConfig"` |
|
56 |
+ // AssetConfig, if present start the asset serverin this process |
|
57 |
+ AssetConfig *AssetConfig `json:"assetConfig"` |
|
58 |
+ // DNSConfig, if present start the DNS server in this process |
|
59 |
+ DNSConfig *DNSConfig `json:"dnsConfig"` |
|
60 |
+ |
|
61 |
+ // MasterClients holds all the client connection information for controllers and other system components |
|
62 |
+ MasterClients MasterClients `json:"masterClients"` |
|
63 |
+ |
|
64 |
+ ImageConfig ImageConfig `json:"imageConfig"` |
|
65 |
+ |
|
66 |
+ // MasterAuthorizationNamespace is the global namespace for Policy |
|
67 |
+ MasterAuthorizationNamespace string `json:"masterAuthorizationNamespace"` |
|
68 |
+ // OpenShiftSharedResourcesNamespace is the namespace where shared OpenShift resources live (like shared templates) |
|
69 |
+ OpenShiftSharedResourcesNamespace string `json:"openshiftSharedResourcesNamespace"` |
|
70 |
+} |
|
71 |
+ |
|
72 |
+type ImageConfig struct { |
|
73 |
+ Format string `json:"format"` |
|
74 |
+ Latest bool `json:"latest"` |
|
75 |
+} |
|
76 |
+ |
|
77 |
+type RemoteConnectionInfo struct { |
|
78 |
+ // URL is the URL for etcd |
|
79 |
+ URL string `json:"url"` |
|
80 |
+ // CA is the CA for confirming that the server at the etcdURL is the actual server |
|
81 |
+ CA string `json:"ca"` |
|
82 |
+ // EtcdClientCertInfo is the TLS client cert information for securing communication to etcd |
|
83 |
+ // this is anonymous so that we can inline it for serialization |
|
84 |
+ CertInfo `json:",inline"` |
|
85 |
+} |
|
86 |
+ |
|
87 |
+type ServingInfo struct { |
|
88 |
+ // BindAddress is the ip:port to serve on |
|
89 |
+ BindAddress string `json:"bindAddress"` |
|
90 |
+ // ServerCert is the TLS cert info for serving secure traffic. |
|
91 |
+ // this is anonymous so that we can inline it for serialization |
|
92 |
+ CertInfo `json:",inline"` |
|
93 |
+ // ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates |
|
94 |
+ ClientCA string `json:"clientCA"` |
|
95 |
+} |
|
96 |
+ |
|
97 |
+type MasterClients struct { |
|
98 |
+ // DeployerKubeConfig is a .kubeconfig filename for depoyment pods to use |
|
99 |
+ DeployerKubeConfig string `json:"deployerKubeConfig"` |
|
100 |
+ // OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master |
|
101 |
+ OpenShiftLoopbackKubeConfig string `json:"openshiftLoopbackKubeConfig"` |
|
102 |
+ // KubernetesKubeConfig is a .kubeconfig filename for system components to communicate to kubernetes for building the proxy |
|
103 |
+ KubernetesKubeConfig string `json:"kubernetesKubeConfig"` |
|
104 |
+} |
|
105 |
+ |
|
106 |
+type DNSConfig struct { |
|
107 |
+ // BindAddress is the ip:port to serve DNS on |
|
108 |
+ BindAddress string `json:"bindAddress"` |
|
109 |
+} |
|
110 |
+ |
|
111 |
+type AssetConfig struct { |
|
112 |
+ ServingInfo ServingInfo `json:"servingInfo"` |
|
113 |
+ |
|
114 |
+ // PublicURL is where you can find the asset server (TODO do we really need this?) |
|
115 |
+ PublicURL string `json:"publicURL"` |
|
116 |
+ |
|
117 |
+ // LogoutURI is an optional, absolute URI to redirect web browsers to after logging out of the web console. |
|
118 |
+ // If not specified, the built-in logout page is shown. |
|
119 |
+ LogoutURI string `json:"logoutURI"` |
|
120 |
+ |
|
121 |
+ // MasterPublicURL is how the web console can access the OpenShift api server |
|
122 |
+ MasterPublicURL string `json:"masterPublicURL"` |
|
123 |
+ |
|
124 |
+ // TODO: we probably don't need this since we have a proxy |
|
125 |
+ // KubernetesPublicURL is how the web console can access the Kubernetes api server |
|
126 |
+ KubernetesPublicURL string `json:"kubernetesPublicURL"` |
|
127 |
+} |
|
128 |
+ |
|
129 |
+type OAuthConfig struct { |
|
130 |
+ // ProxyCA is the certificate bundle for confirming the identity of front proxy forwards to the oauth server |
|
131 |
+ ProxyCA string `json:"proxyCA"` |
|
132 |
+ |
|
133 |
+ // MasterURL is used for building valid client redirect URLs for external access |
|
134 |
+ MasterURL string `json:"masterURL"` |
|
135 |
+ |
|
136 |
+ // MasterPublicURL is used for building valid client redirect URLs for external access |
|
137 |
+ MasterPublicURL string `json:"masterPublicURL"` |
|
138 |
+ |
|
139 |
+ // AssetPublicURL is used for building valid client redirect URLs for external access |
|
140 |
+ AssetPublicURL string `json:"assetPublicURL"` |
|
141 |
+ |
|
142 |
+ // all the handlers here |
|
143 |
+} |
|
144 |
+ |
|
145 |
+type EtcdConfig struct { |
|
146 |
+ ServingInfo ServingInfo `json:"servingInfo"` |
|
147 |
+ |
|
148 |
+ PeerAddress string `json:"peerAddress"` |
|
149 |
+ MasterAddress string `json:"masterAddress"` |
|
150 |
+ StorageDir string `json:"storageDirectory"` |
|
151 |
+} |
|
152 |
+ |
|
153 |
+type KubernetesMasterConfig struct { |
|
154 |
+ ServicesSubnet string `json:"servicesSubnet"` |
|
155 |
+ StaticNodeNames []string `json:"staticNodeNames"` |
|
156 |
+} |
|
157 |
+ |
|
158 |
+type CertInfo struct { |
|
159 |
+ CertFile string `json:"certFile"` |
|
160 |
+ KeyFile string `json:"keyFile"` |
|
161 |
+} |
... | ... |
@@ -16,6 +16,7 @@ const ( |
16 | 16 |
AuthenticatedGroup = "system:authenticated" |
17 | 17 |
UnauthenticatedGroup = "system:unauthenticated" |
18 | 18 |
ClusterAdminGroup = "system:cluster-admins" |
19 |
+ NodesGroup = "system:nodes" |
|
19 | 20 |
) |
20 | 21 |
|
21 | 22 |
const ( |
... | ... |
@@ -226,7 +227,8 @@ func GetBootstrapMasterRoleBindings(masterNamespace string) []authorizationapi.R |
226 | 226 |
Name: InternalComponentRoleName, |
227 | 227 |
Namespace: masterNamespace, |
228 | 228 |
}, |
229 |
- Users: util.NewStringSet(InternalComponentUsername, InternalComponentKubeUsername), |
|
229 |
+ Users: util.NewStringSet(InternalComponentUsername, InternalComponentKubeUsername), |
|
230 |
+ Groups: util.NewStringSet(NodesGroup), |
|
230 | 231 |
}, |
231 | 232 |
{ |
232 | 233 |
ObjectMeta: kapi.ObjectMeta{ |
233 | 234 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,182 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "path" |
|
6 |
+ "path/filepath" |
|
7 |
+ |
|
8 |
+ "github.com/golang/glog" |
|
9 |
+ "github.com/spf13/cobra" |
|
10 |
+ |
|
11 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+type CreateAllCertsOptions struct { |
|
15 |
+ CertDir string |
|
16 |
+ SignerName string |
|
17 |
+ |
|
18 |
+ Hostnames util.StringList |
|
19 |
+ NodeList util.StringList |
|
20 |
+ |
|
21 |
+ APIServerURL string |
|
22 |
+ PublicAPIServerURL string |
|
23 |
+ |
|
24 |
+ Overwrite bool |
|
25 |
+} |
|
26 |
+ |
|
27 |
+func NewCommandCreateAllCerts() *cobra.Command { |
|
28 |
+ options := &CreateAllCertsOptions{} |
|
29 |
+ |
|
30 |
+ cmd := &cobra.Command{ |
|
31 |
+ Use: "create-all-certs", |
|
32 |
+ Short: "Create all certificates for OpenShift All-In-One", |
|
33 |
+ Run: func(c *cobra.Command, args []string) { |
|
34 |
+ if err := options.Validate(args); err != nil { |
|
35 |
+ fmt.Println(err.Error()) |
|
36 |
+ c.Help() |
|
37 |
+ return |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ if err := options.CreateAllCerts(); err != nil { |
|
41 |
+ glog.Fatal(err) |
|
42 |
+ } |
|
43 |
+ }, |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ flags := cmd.Flags() |
|
47 |
+ |
|
48 |
+ flags.StringVar(&options.CertDir, "cert-dir", "openshift.local.certificates", "The certificate data directory.") |
|
49 |
+ flags.StringVar(&options.SignerName, "signer-name", DefaultSignerName(), "The name to use for the generated signer.") |
|
50 |
+ |
|
51 |
+ flags.StringVar(&options.APIServerURL, "master", "https://localhost:8443", "The API server's URL.") |
|
52 |
+ flags.StringVar(&options.PublicAPIServerURL, "public-master", "", "The API public facing server's URL (if applicable).") |
|
53 |
+ flags.Var(&options.Hostnames, "hostnames", "Every hostname or IP you want server certs to be valid for. Comma delimited list") |
|
54 |
+ flags.Var(&options.NodeList, "nodes", "The names of all static nodes you'd like to generate certificates for. Comma delimited list") |
|
55 |
+ flags.BoolVar(&options.Overwrite, "overwrite", true, "Overwrite existing cert files if found. If false, any existing file will be left as-is.") |
|
56 |
+ |
|
57 |
+ return cmd |
|
58 |
+} |
|
59 |
+ |
|
60 |
+func (o CreateAllCertsOptions) Validate(args []string) error { |
|
61 |
+ if len(args) != 0 { |
|
62 |
+ return errors.New("no arguments are supported") |
|
63 |
+ } |
|
64 |
+ if len(o.Hostnames) == 0 { |
|
65 |
+ return errors.New("at least one hostname must be provided") |
|
66 |
+ } |
|
67 |
+ if len(o.CertDir) == 0 { |
|
68 |
+ return errors.New("cert-dir must be provided") |
|
69 |
+ } |
|
70 |
+ if len(o.SignerName) == 0 { |
|
71 |
+ return errors.New("signer-name must be provided") |
|
72 |
+ } |
|
73 |
+ if len(o.APIServerURL) == 0 { |
|
74 |
+ return errors.New("master must be provided") |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ return nil |
|
78 |
+} |
|
79 |
+ |
|
80 |
+func (o CreateAllCertsOptions) CreateAllCerts() error { |
|
81 |
+ glog.V(2).Infof("Creating all certs with: %#v", o) |
|
82 |
+ |
|
83 |
+ signerCertOptions := CreateSignerCertOptions{ |
|
84 |
+ CertFile: DefaultCertFilename(o.CertDir, DefaultCADir), |
|
85 |
+ KeyFile: DefaultKeyFilename(o.CertDir, DefaultCADir), |
|
86 |
+ SerialFile: DefaultSerialFilename(o.CertDir, DefaultCADir), |
|
87 |
+ Name: o.SignerName, |
|
88 |
+ Overwrite: o.Overwrite, |
|
89 |
+ } |
|
90 |
+ if _, err := signerCertOptions.CreateSignerCert(); err != nil { |
|
91 |
+ return err |
|
92 |
+ } |
|
93 |
+ // once we've minted the signer, don't overwrite it |
|
94 |
+ getSignerCertOptions := GetSignerCertOptions{ |
|
95 |
+ CertFile: DefaultCertFilename(o.CertDir, DefaultCADir), |
|
96 |
+ KeyFile: DefaultKeyFilename(o.CertDir, DefaultCADir), |
|
97 |
+ SerialFile: DefaultSerialFilename(o.CertDir, DefaultCADir), |
|
98 |
+ } |
|
99 |
+ |
|
100 |
+ for _, clientCertInfo := range DefaultClientCerts(o.CertDir) { |
|
101 |
+ clientCertOptions := CreateClientCertOptions{ |
|
102 |
+ GetSignerCertOptions: &getSignerCertOptions, |
|
103 |
+ |
|
104 |
+ CertFile: clientCertInfo.CertLocation.CertFile, |
|
105 |
+ KeyFile: clientCertInfo.CertLocation.KeyFile, |
|
106 |
+ |
|
107 |
+ User: clientCertInfo.User, |
|
108 |
+ Groups: util.StringList(clientCertInfo.Groups.List()), |
|
109 |
+ Overwrite: o.Overwrite, |
|
110 |
+ } |
|
111 |
+ if _, err := clientCertOptions.CreateClientCert(); err != nil { |
|
112 |
+ return err |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ createKubeConfigOptions := CreateKubeConfigOptions{ |
|
116 |
+ APIServerURL: o.APIServerURL, |
|
117 |
+ PublicAPIServerURL: o.PublicAPIServerURL, |
|
118 |
+ APIServerCAFile: getSignerCertOptions.CertFile, |
|
119 |
+ ServerNick: "master", |
|
120 |
+ |
|
121 |
+ CertFile: clientCertInfo.CertLocation.CertFile, |
|
122 |
+ KeyFile: clientCertInfo.CertLocation.KeyFile, |
|
123 |
+ UserNick: clientCertInfo.SubDir, |
|
124 |
+ |
|
125 |
+ KubeConfigFile: path.Join(filepath.Dir(clientCertOptions.CertFile), ".kubeconfig"), |
|
126 |
+ } |
|
127 |
+ if _, err := createKubeConfigOptions.CreateKubeConfig(); err != nil { |
|
128 |
+ return err |
|
129 |
+ } |
|
130 |
+ } |
|
131 |
+ |
|
132 |
+ for _, nodeName := range o.NodeList { |
|
133 |
+ username := "node-" + nodeName |
|
134 |
+ nodeCertOptions := CreateNodeClientCertOptions{ |
|
135 |
+ GetSignerCertOptions: &getSignerCertOptions, |
|
136 |
+ |
|
137 |
+ CertFile: DefaultCertFilename(o.CertDir, username), |
|
138 |
+ KeyFile: DefaultKeyFilename(o.CertDir, username), |
|
139 |
+ |
|
140 |
+ NodeName: nodeName, |
|
141 |
+ Overwrite: o.Overwrite, |
|
142 |
+ } |
|
143 |
+ if _, err := nodeCertOptions.CreateNodeClientCert(); err != nil { |
|
144 |
+ return err |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ createKubeConfigOptions := CreateKubeConfigOptions{ |
|
148 |
+ APIServerURL: o.APIServerURL, |
|
149 |
+ PublicAPIServerURL: o.PublicAPIServerURL, |
|
150 |
+ APIServerCAFile: getSignerCertOptions.CertFile, |
|
151 |
+ ServerNick: "master", |
|
152 |
+ |
|
153 |
+ CertFile: nodeCertOptions.CertFile, |
|
154 |
+ KeyFile: nodeCertOptions.KeyFile, |
|
155 |
+ UserNick: username, |
|
156 |
+ |
|
157 |
+ KubeConfigFile: path.Join(filepath.Dir(nodeCertOptions.CertFile), ".kubeconfig"), |
|
158 |
+ } |
|
159 |
+ if _, err := createKubeConfigOptions.CreateKubeConfig(); err != nil { |
|
160 |
+ return err |
|
161 |
+ } |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ for _, serverCertInfo := range DefaultServerCerts(o.CertDir) { |
|
165 |
+ serverCertOptions := CreateServerCertOptions{ |
|
166 |
+ GetSignerCertOptions: &getSignerCertOptions, |
|
167 |
+ |
|
168 |
+ CertFile: serverCertInfo.CertFile, |
|
169 |
+ KeyFile: serverCertInfo.KeyFile, |
|
170 |
+ |
|
171 |
+ Hostnames: o.Hostnames, |
|
172 |
+ Overwrite: o.Overwrite, |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ if _, err := serverCertOptions.CreateServerCert(); err != nil { |
|
176 |
+ return err |
|
177 |
+ } |
|
178 |
+ } |
|
179 |
+ |
|
180 |
+ return nil |
|
181 |
+} |
0 | 182 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,93 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ |
|
6 |
+ "github.com/golang/glog" |
|
7 |
+ "github.com/spf13/cobra" |
|
8 |
+ |
|
9 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
|
10 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
11 |
+ |
|
12 |
+ "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
13 |
+) |
|
14 |
+ |
|
15 |
+type CreateClientCertOptions struct { |
|
16 |
+ GetSignerCertOptions *GetSignerCertOptions |
|
17 |
+ |
|
18 |
+ CertFile string |
|
19 |
+ KeyFile string |
|
20 |
+ |
|
21 |
+ User string |
|
22 |
+ Groups util.StringList |
|
23 |
+ |
|
24 |
+ Overwrite bool |
|
25 |
+} |
|
26 |
+ |
|
27 |
+func NewCommandCreateClientCert() *cobra.Command { |
|
28 |
+ options := &CreateClientCertOptions{GetSignerCertOptions: &GetSignerCertOptions{}} |
|
29 |
+ |
|
30 |
+ cmd := &cobra.Command{ |
|
31 |
+ Use: "create-client-cert", |
|
32 |
+ Short: "Create client certificate", |
|
33 |
+ Run: func(c *cobra.Command, args []string) { |
|
34 |
+ if err := options.Validate(args); err != nil { |
|
35 |
+ fmt.Println(err.Error()) |
|
36 |
+ c.Help() |
|
37 |
+ return |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ if _, err := options.CreateClientCert(); err != nil { |
|
41 |
+ fmt.Println(err.Error()) |
|
42 |
+ c.Help() |
|
43 |
+ return |
|
44 |
+ } |
|
45 |
+ }, |
|
46 |
+ } |
|
47 |
+ |
|
48 |
+ flags := cmd.Flags() |
|
49 |
+ BindGetSignerCertOptions(options.GetSignerCertOptions, flags, "") |
|
50 |
+ |
|
51 |
+ flags.StringVar(&options.CertFile, "cert", "openshift.local.certificates/user/cert.crt", "The certificate file.") |
|
52 |
+ flags.StringVar(&options.KeyFile, "key", "openshift.local.certificates/user/key.key", "The key file.") |
|
53 |
+ |
|
54 |
+ flags.StringVar(&options.User, "user", "", "The scope qualified username.") |
|
55 |
+ flags.Var(&options.Groups, "groups", "The list of groups this user belongs to. Comma delimited list") |
|
56 |
+ flags.BoolVar(&options.Overwrite, "overwrite", true, "Overwrite existing cert files if found. If false, any existing file will be left as-is.") |
|
57 |
+ |
|
58 |
+ return cmd |
|
59 |
+} |
|
60 |
+ |
|
61 |
+func (o CreateClientCertOptions) Validate(args []string) error { |
|
62 |
+ if len(args) != 0 { |
|
63 |
+ return errors.New("no arguments are supported") |
|
64 |
+ } |
|
65 |
+ if len(o.CertFile) == 0 { |
|
66 |
+ return errors.New("cert must be provided") |
|
67 |
+ } |
|
68 |
+ if len(o.KeyFile) == 0 { |
|
69 |
+ return errors.New("key must be provided") |
|
70 |
+ } |
|
71 |
+ if len(o.User) == 0 { |
|
72 |
+ return errors.New("user must be provided") |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ return o.GetSignerCertOptions.Validate() |
|
76 |
+} |
|
77 |
+ |
|
78 |
+func (o CreateClientCertOptions) CreateClientCert() (*crypto.TLSCertificateConfig, error) { |
|
79 |
+ glog.V(2).Infof("Createing a client cert with: %#v and %#v", o, o.GetSignerCertOptions) |
|
80 |
+ |
|
81 |
+ signerCert, err := o.GetSignerCertOptions.GetSignerCert() |
|
82 |
+ if err != nil { |
|
83 |
+ return nil, err |
|
84 |
+ } |
|
85 |
+ |
|
86 |
+ userInfo := &user.DefaultInfo{Name: o.User, Groups: o.Groups} |
|
87 |
+ if o.Overwrite { |
|
88 |
+ return signerCert.MakeClientCertificate(o.CertFile, o.KeyFile, userInfo) |
|
89 |
+ } else { |
|
90 |
+ return signerCert.EnsureClientCertificate(o.CertFile, o.KeyFile, userInfo) |
|
91 |
+ } |
|
92 |
+} |
0 | 93 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,24 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/spf13/cobra" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+func NewCommandAdmin() *cobra.Command { |
|
7 |
+ cmd := &cobra.Command{ |
|
8 |
+ Use: "admin", |
|
9 |
+ Short: "Admin commands", |
|
10 |
+ Run: func(c *cobra.Command, args []string) { |
|
11 |
+ c.Help() |
|
12 |
+ }, |
|
13 |
+ } |
|
14 |
+ |
|
15 |
+ cmd.AddCommand(NewCommandCreateKubeConfig()) |
|
16 |
+ cmd.AddCommand(NewCommandCreateAllCerts()) |
|
17 |
+ cmd.AddCommand(NewCommandCreateClientCert()) |
|
18 |
+ cmd.AddCommand(NewCommandCreateNodeClientCert()) |
|
19 |
+ cmd.AddCommand(NewCommandCreateServerCert()) |
|
20 |
+ cmd.AddCommand(NewCommandCreateSignerCert()) |
|
21 |
+ |
|
22 |
+ return cmd |
|
23 |
+} |
0 | 24 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,162 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "io/ioutil" |
|
6 |
+ "os" |
|
7 |
+ "path/filepath" |
|
8 |
+ |
|
9 |
+ "github.com/golang/glog" |
|
10 |
+ "github.com/spf13/cobra" |
|
11 |
+ |
|
12 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
13 |
+ clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" |
|
14 |
+) |
|
15 |
+ |
|
16 |
+type CreateKubeConfigOptions struct { |
|
17 |
+ APIServerURL string |
|
18 |
+ PublicAPIServerURL string |
|
19 |
+ APIServerCAFile string |
|
20 |
+ ServerNick string |
|
21 |
+ |
|
22 |
+ CertFile string |
|
23 |
+ KeyFile string |
|
24 |
+ UserNick string |
|
25 |
+ |
|
26 |
+ KubeConfigFile string |
|
27 |
+} |
|
28 |
+ |
|
29 |
+func NewCommandCreateKubeConfig() *cobra.Command { |
|
30 |
+ options := &CreateKubeConfigOptions{} |
|
31 |
+ |
|
32 |
+ cmd := &cobra.Command{ |
|
33 |
+ Use: "create-kubeconfig", |
|
34 |
+ Short: "Create a basic .kubeconfig file from client certs", |
|
35 |
+ Long: ` |
|
36 |
+Create's a .kubeconfig file at <--kubeconfig> that looks like this: |
|
37 |
+ |
|
38 |
+clusters: |
|
39 |
+- cluster: |
|
40 |
+ certificate-authority-data: <contents of --certificate-authority> |
|
41 |
+ server: <--master> |
|
42 |
+ name: <--cluster> |
|
43 |
+- cluster: |
|
44 |
+ certificate-authority-data: <contents of --certificate-authority> |
|
45 |
+ server: <--public-master> |
|
46 |
+ name: public-<--cluster> |
|
47 |
+contexts: |
|
48 |
+- context: |
|
49 |
+ cluster: <--cluster> |
|
50 |
+ user: <--user> |
|
51 |
+ name: <--cluster> |
|
52 |
+current-context: <--cluster> |
|
53 |
+kind: Config |
|
54 |
+users: |
|
55 |
+- name: <--user> |
|
56 |
+ user: |
|
57 |
+ client-certificate-data: <contents of --client-certificate> |
|
58 |
+ client-key-data: <contents of --client-key> |
|
59 |
+`, |
|
60 |
+ Run: func(c *cobra.Command, args []string) { |
|
61 |
+ if err := options.Validate(args); err != nil { |
|
62 |
+ fmt.Println(err.Error()) |
|
63 |
+ c.Help() |
|
64 |
+ return |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ if _, err := options.CreateKubeConfig(); err != nil { |
|
68 |
+ glog.Fatal(err) |
|
69 |
+ } |
|
70 |
+ }, |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ flags := cmd.Flags() |
|
74 |
+ |
|
75 |
+ flags.StringVar(&options.APIServerURL, "master", "https://localhost:8443", "The API server's URL.") |
|
76 |
+ flags.StringVar(&options.PublicAPIServerURL, "public-master", "", "The API public facing server's URL (if applicable).") |
|
77 |
+ flags.StringVar(&options.APIServerCAFile, "certificate-authority", "openshift.local.certificates/ca/cert.crt", "Path to the API server's CA file.") |
|
78 |
+ flags.StringVar(&options.ServerNick, "cluster", "master", "Nick name for this server in .kubeconfig.") |
|
79 |
+ flags.StringVar(&options.CertFile, "client-certificate", "openshift.local.certificates/admin/cert.crt", "The client cert file.") |
|
80 |
+ flags.StringVar(&options.KeyFile, "client-key", "openshift.local.certificates/admin/key.key", "The client key file.") |
|
81 |
+ flags.StringVar(&options.UserNick, "user", "user", "Nick name for this user in .kubeconfig.") |
|
82 |
+ flags.StringVar(&options.KubeConfigFile, "kubeconfig", ".kubeconfig", "Path for the resulting .kubeconfig file.") |
|
83 |
+ |
|
84 |
+ return cmd |
|
85 |
+} |
|
86 |
+ |
|
87 |
+func (o CreateKubeConfigOptions) Validate(args []string) error { |
|
88 |
+ if len(args) != 0 { |
|
89 |
+ return errors.New("no arguments are supported") |
|
90 |
+ } |
|
91 |
+ if len(o.KubeConfigFile) == 0 { |
|
92 |
+ return errors.New("kubeconfig must be provided") |
|
93 |
+ } |
|
94 |
+ if len(o.ServerNick) == 0 { |
|
95 |
+ return errors.New("cluster must be provided") |
|
96 |
+ } |
|
97 |
+ if len(o.UserNick) == 0 { |
|
98 |
+ return errors.New("user-nick must be provided") |
|
99 |
+ } |
|
100 |
+ |
|
101 |
+ return nil |
|
102 |
+} |
|
103 |
+ |
|
104 |
+func (o CreateKubeConfigOptions) CreateKubeConfig() (*clientcmdapi.Config, error) { |
|
105 |
+ glog.V(2).Infof("creating a .kubeconfig with: %#v", o) |
|
106 |
+ |
|
107 |
+ caData, err := ioutil.ReadFile(o.APIServerCAFile) |
|
108 |
+ if err != nil { |
|
109 |
+ return nil, err |
|
110 |
+ } |
|
111 |
+ certData, err := ioutil.ReadFile(o.CertFile) |
|
112 |
+ if err != nil { |
|
113 |
+ return nil, err |
|
114 |
+ } |
|
115 |
+ keyData, err := ioutil.ReadFile(o.KeyFile) |
|
116 |
+ if err != nil { |
|
117 |
+ return nil, err |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ credentials := make(map[string]clientcmdapi.AuthInfo) |
|
121 |
+ credentials[o.UserNick] = clientcmdapi.AuthInfo{ |
|
122 |
+ ClientCertificateData: certData, |
|
123 |
+ ClientKeyData: keyData, |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ clusters := make(map[string]clientcmdapi.Cluster) |
|
127 |
+ clusters[o.ServerNick] = clientcmdapi.Cluster{ |
|
128 |
+ Server: o.APIServerURL, |
|
129 |
+ CertificateAuthorityData: caData, |
|
130 |
+ } |
|
131 |
+ |
|
132 |
+ contexts := make(map[string]clientcmdapi.Context) |
|
133 |
+ contexts[o.ServerNick] = clientcmdapi.Context{Cluster: o.ServerNick, AuthInfo: o.UserNick} |
|
134 |
+ |
|
135 |
+ createPublic := len(o.PublicAPIServerURL) > 0 |
|
136 |
+ if createPublic { |
|
137 |
+ publicNick := "public-" + o.ServerNick |
|
138 |
+ clusters[publicNick] = clientcmdapi.Cluster{ |
|
139 |
+ Server: o.PublicAPIServerURL, |
|
140 |
+ CertificateAuthorityData: caData, |
|
141 |
+ } |
|
142 |
+ contexts[publicNick] = clientcmdapi.Context{Cluster: o.ServerNick, AuthInfo: o.UserNick} |
|
143 |
+ } |
|
144 |
+ |
|
145 |
+ kubeConfig := &clientcmdapi.Config{ |
|
146 |
+ Clusters: clusters, |
|
147 |
+ AuthInfos: credentials, |
|
148 |
+ Contexts: contexts, |
|
149 |
+ CurrentContext: o.ServerNick, |
|
150 |
+ } |
|
151 |
+ |
|
152 |
+ // Ensure the parent dir exists |
|
153 |
+ if err := os.MkdirAll(filepath.Dir(o.KubeConfigFile), os.FileMode(0755)); err != nil { |
|
154 |
+ return nil, err |
|
155 |
+ } |
|
156 |
+ if err := clientcmd.WriteToFile(*kubeConfig, o.KubeConfigFile); err != nil { |
|
157 |
+ return nil, err |
|
158 |
+ } |
|
159 |
+ |
|
160 |
+ return kubeConfig, nil |
|
161 |
+} |
0 | 162 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,91 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ |
|
6 |
+ "github.com/golang/glog" |
|
7 |
+ "github.com/spf13/cobra" |
|
8 |
+ |
|
9 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
10 |
+ |
|
11 |
+ "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+type CreateNodeClientCertOptions struct { |
|
15 |
+ GetSignerCertOptions *GetSignerCertOptions |
|
16 |
+ |
|
17 |
+ CertFile string |
|
18 |
+ KeyFile string |
|
19 |
+ |
|
20 |
+ NodeName string |
|
21 |
+ |
|
22 |
+ Overwrite bool |
|
23 |
+} |
|
24 |
+ |
|
25 |
+func NewCommandCreateNodeClientCert() *cobra.Command { |
|
26 |
+ options := &CreateNodeClientCertOptions{GetSignerCertOptions: &GetSignerCertOptions{}} |
|
27 |
+ |
|
28 |
+ cmd := &cobra.Command{ |
|
29 |
+ Use: "create-node-cert", |
|
30 |
+ Short: "Create node certificate", |
|
31 |
+ Run: func(c *cobra.Command, args []string) { |
|
32 |
+ if err := options.Validate(args); err != nil { |
|
33 |
+ fmt.Println(err.Error()) |
|
34 |
+ c.Help() |
|
35 |
+ return |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ if _, err := options.CreateNodeClientCert(); err != nil { |
|
39 |
+ glog.Fatal(err) |
|
40 |
+ } |
|
41 |
+ }, |
|
42 |
+ } |
|
43 |
+ |
|
44 |
+ flags := cmd.Flags() |
|
45 |
+ BindGetSignerCertOptions(options.GetSignerCertOptions, flags, "") |
|
46 |
+ |
|
47 |
+ flags.StringVar(&options.CertFile, "cert", "openshift.local.certificates/user/cert.crt", "The certificate file.") |
|
48 |
+ flags.StringVar(&options.KeyFile, "key", "openshift.local.certificates/user/key.key", "The key file.") |
|
49 |
+ |
|
50 |
+ flags.StringVar(&options.NodeName, "node-name", "", "The name of the node.") |
|
51 |
+ flags.BoolVar(&options.Overwrite, "overwrite", true, "Overwrite existing cert files if found. If false, any existing file will be left as-is.") |
|
52 |
+ |
|
53 |
+ return cmd |
|
54 |
+} |
|
55 |
+ |
|
56 |
+func (o CreateNodeClientCertOptions) Validate(args []string) error { |
|
57 |
+ if len(args) != 0 { |
|
58 |
+ return errors.New("no arguments are supported") |
|
59 |
+ } |
|
60 |
+ if len(o.CertFile) == 0 { |
|
61 |
+ return errors.New("cert must be provided") |
|
62 |
+ } |
|
63 |
+ if len(o.KeyFile) == 0 { |
|
64 |
+ return errors.New("key must be provided") |
|
65 |
+ } |
|
66 |
+ if len(o.NodeName) == 0 { |
|
67 |
+ return errors.New("node-name must be provided") |
|
68 |
+ } |
|
69 |
+ |
|
70 |
+ return o.GetSignerCertOptions.Validate() |
|
71 |
+} |
|
72 |
+ |
|
73 |
+func (o CreateNodeClientCertOptions) CreateNodeClientCert() (*crypto.TLSCertificateConfig, error) { |
|
74 |
+ glog.V(2).Infof("Createing a node client cert with: %#v and %#v", o, o.GetSignerCertOptions) |
|
75 |
+ |
|
76 |
+ username := "node-" + o.NodeName |
|
77 |
+ |
|
78 |
+ nodeCertOptions := CreateClientCertOptions{ |
|
79 |
+ GetSignerCertOptions: o.GetSignerCertOptions, |
|
80 |
+ |
|
81 |
+ CertFile: o.CertFile, |
|
82 |
+ KeyFile: o.KeyFile, |
|
83 |
+ |
|
84 |
+ User: "system:" + username, |
|
85 |
+ Groups: util.StringList([]string{"system:nodes"}), |
|
86 |
+ Overwrite: o.Overwrite, |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ return nodeCertOptions.CreateClientCert() |
|
90 |
+} |
0 | 91 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,86 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ |
|
6 |
+ "github.com/golang/glog" |
|
7 |
+ "github.com/spf13/cobra" |
|
8 |
+ |
|
9 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
10 |
+ |
|
11 |
+ "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+type CreateServerCertOptions struct { |
|
15 |
+ GetSignerCertOptions *GetSignerCertOptions |
|
16 |
+ |
|
17 |
+ CertFile string |
|
18 |
+ KeyFile string |
|
19 |
+ |
|
20 |
+ Hostnames util.StringList |
|
21 |
+ Overwrite bool |
|
22 |
+} |
|
23 |
+ |
|
24 |
+func NewCommandCreateServerCert() *cobra.Command { |
|
25 |
+ options := &CreateServerCertOptions{GetSignerCertOptions: &GetSignerCertOptions{}} |
|
26 |
+ |
|
27 |
+ cmd := &cobra.Command{ |
|
28 |
+ Use: "create-server-cert", |
|
29 |
+ Short: "Create server certificate", |
|
30 |
+ Run: func(c *cobra.Command, args []string) { |
|
31 |
+ if err := options.Validate(args); err != nil { |
|
32 |
+ fmt.Println(err.Error()) |
|
33 |
+ c.Help() |
|
34 |
+ return |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ if _, err := options.CreateServerCert(); err != nil { |
|
38 |
+ glog.Fatal(err) |
|
39 |
+ } |
|
40 |
+ }, |
|
41 |
+ } |
|
42 |
+ |
|
43 |
+ flags := cmd.Flags() |
|
44 |
+ BindGetSignerCertOptions(options.GetSignerCertOptions, flags, "signer-") |
|
45 |
+ |
|
46 |
+ flags.StringVar(&options.CertFile, "cert", "openshift.local.certificates/user/cert.crt", "The certificate file.") |
|
47 |
+ flags.StringVar(&options.KeyFile, "key", "openshift.local.certificates/user/key.key", "The key file.") |
|
48 |
+ |
|
49 |
+ flags.Var(&options.Hostnames, "hostnames", "Every hostname or IP you want server certs to be valid for. Comma delimited list") |
|
50 |
+ flags.BoolVar(&options.Overwrite, "overwrite", true, "Overwrite existing cert files if found. If false, any existing file will be left as-is.") |
|
51 |
+ |
|
52 |
+ return cmd |
|
53 |
+} |
|
54 |
+ |
|
55 |
+func (o CreateServerCertOptions) Validate(args []string) error { |
|
56 |
+ if len(args) != 0 { |
|
57 |
+ return errors.New("no arguments are supported") |
|
58 |
+ } |
|
59 |
+ if len(o.Hostnames) == 0 { |
|
60 |
+ return errors.New("at least one hostname must be provided") |
|
61 |
+ } |
|
62 |
+ if len(o.CertFile) == 0 { |
|
63 |
+ return errors.New("cert must be provided") |
|
64 |
+ } |
|
65 |
+ if len(o.KeyFile) == 0 { |
|
66 |
+ return errors.New("key must be provided") |
|
67 |
+ } |
|
68 |
+ |
|
69 |
+ return o.GetSignerCertOptions.Validate() |
|
70 |
+} |
|
71 |
+ |
|
72 |
+func (o CreateServerCertOptions) CreateServerCert() (*crypto.TLSCertificateConfig, error) { |
|
73 |
+ glog.V(2).Infof("Createing a server cert with: %#v", o) |
|
74 |
+ |
|
75 |
+ signerCert, err := o.GetSignerCertOptions.GetSignerCert() |
|
76 |
+ if err != nil { |
|
77 |
+ return nil, err |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ if o.Overwrite { |
|
81 |
+ return signerCert.MakeServerCert(o.CertFile, o.KeyFile, util.NewStringSet([]string(o.Hostnames)...)) |
|
82 |
+ } else { |
|
83 |
+ return signerCert.EnsureServerCert(o.CertFile, o.KeyFile, util.NewStringSet([]string(o.Hostnames)...)) |
|
84 |
+ } |
|
85 |
+} |
0 | 86 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,83 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ |
|
6 |
+ "github.com/golang/glog" |
|
7 |
+ "github.com/spf13/cobra" |
|
8 |
+ "github.com/spf13/pflag" |
|
9 |
+ |
|
10 |
+ "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+type CreateSignerCertOptions struct { |
|
14 |
+ CertFile string |
|
15 |
+ KeyFile string |
|
16 |
+ SerialFile string |
|
17 |
+ Name string |
|
18 |
+ |
|
19 |
+ Overwrite bool |
|
20 |
+} |
|
21 |
+ |
|
22 |
+func BindSignerCertOptions(options *CreateSignerCertOptions, flags *pflag.FlagSet, prefix string) { |
|
23 |
+ flags.StringVar(&options.CertFile, prefix+"cert", "openshift.local.certificates/ca/cert.crt", "The certificate file.") |
|
24 |
+ flags.StringVar(&options.KeyFile, prefix+"key", "openshift.local.certificates/ca/key.key", "The key file.") |
|
25 |
+ flags.StringVar(&options.SerialFile, prefix+"serial", "openshift.local.certificates/ca/serial.txt", "The serial file that keeps track of how many certs have been signed.") |
|
26 |
+ flags.StringVar(&options.Name, prefix+"name", DefaultSignerName(), "The name of the signer.") |
|
27 |
+ flags.BoolVar(&options.Overwrite, prefix+"overwrite", options.Overwrite, "Overwrite existing cert files if found. If false, any existing file will be left as-is.") |
|
28 |
+} |
|
29 |
+ |
|
30 |
+func NewCommandCreateSignerCert() *cobra.Command { |
|
31 |
+ options := &CreateSignerCertOptions{Overwrite: true} |
|
32 |
+ |
|
33 |
+ cmd := &cobra.Command{ |
|
34 |
+ Use: "create-signer-cert", |
|
35 |
+ Short: "Create signer certificate", |
|
36 |
+ Run: func(c *cobra.Command, args []string) { |
|
37 |
+ if err := options.Validate(args); err != nil { |
|
38 |
+ fmt.Println(err.Error()) |
|
39 |
+ c.Help() |
|
40 |
+ return |
|
41 |
+ } |
|
42 |
+ |
|
43 |
+ if _, err := options.CreateSignerCert(); err != nil { |
|
44 |
+ glog.Fatal(err) |
|
45 |
+ } |
|
46 |
+ }, |
|
47 |
+ } |
|
48 |
+ |
|
49 |
+ BindSignerCertOptions(options, cmd.Flags(), "") |
|
50 |
+ |
|
51 |
+ return cmd |
|
52 |
+} |
|
53 |
+ |
|
54 |
+func (o CreateSignerCertOptions) Validate(args []string) error { |
|
55 |
+ if len(args) != 0 { |
|
56 |
+ return errors.New("no arguments are supported") |
|
57 |
+ } |
|
58 |
+ if len(o.CertFile) == 0 { |
|
59 |
+ return errors.New("cert must be provided") |
|
60 |
+ } |
|
61 |
+ if len(o.KeyFile) == 0 { |
|
62 |
+ return errors.New("key must be provided") |
|
63 |
+ } |
|
64 |
+ if len(o.SerialFile) == 0 { |
|
65 |
+ return errors.New("serial must be provided") |
|
66 |
+ } |
|
67 |
+ if len(o.Name) == 0 { |
|
68 |
+ return errors.New("name must be provided") |
|
69 |
+ } |
|
70 |
+ |
|
71 |
+ return nil |
|
72 |
+} |
|
73 |
+ |
|
74 |
+func (o CreateSignerCertOptions) CreateSignerCert() (*crypto.CA, error) { |
|
75 |
+ glog.V(2).Infof("Createing a signer cert with: %#v", o) |
|
76 |
+ |
|
77 |
+ if o.Overwrite { |
|
78 |
+ return crypto.MakeCA(o.CertFile, o.KeyFile, o.SerialFile, o.Name) |
|
79 |
+ } else { |
|
80 |
+ return crypto.EnsureCA(o.CertFile, o.KeyFile, o.SerialFile, o.Name) |
|
81 |
+ } |
|
82 |
+} |
0 | 83 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,131 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ "path" |
|
5 |
+ "time" |
|
6 |
+ |
|
7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
8 |
+ |
|
9 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
10 |
+) |
|
11 |
+ |
|
12 |
+const ( |
|
13 |
+ DefaultCADir = "ca" |
|
14 |
+) |
|
15 |
+ |
|
16 |
+type ClientCertInfo struct { |
|
17 |
+ CertLocation configapi.CertInfo |
|
18 |
+ SubDir string |
|
19 |
+ User string |
|
20 |
+ Groups util.StringSet |
|
21 |
+} |
|
22 |
+ |
|
23 |
+func DefaultSignerName() string { |
|
24 |
+ return fmt.Sprintf("%s@%d", "openshift-signer", time.Now().Unix()) |
|
25 |
+} |
|
26 |
+ |
|
27 |
+func DefaultRootCAFile(certDir string) string { |
|
28 |
+ return DefaultCertFilename(certDir, DefaultCADir) |
|
29 |
+} |
|
30 |
+ |
|
31 |
+func DefaultClientCerts(certDir string) []ClientCertInfo { |
|
32 |
+ return []ClientCertInfo{ |
|
33 |
+ DefaultDeployerClientCertInfo(certDir), |
|
34 |
+ DefaultOpenshiftLoopbackClientCertInfo(certDir), |
|
35 |
+ DefaultKubeClientClientCertInfo(certDir), |
|
36 |
+ DefaultClusterAdminClientCertInfo(certDir), |
|
37 |
+ } |
|
38 |
+} |
|
39 |
+ |
|
40 |
+func DefaultDeployerClientCertInfo(certDir string) ClientCertInfo { |
|
41 |
+ return ClientCertInfo{ |
|
42 |
+ CertLocation: configapi.CertInfo{ |
|
43 |
+ CertFile: DefaultCertFilename(certDir, "openshift-deployer"), |
|
44 |
+ KeyFile: DefaultKeyFilename(certDir, "openshift-deployer"), |
|
45 |
+ }, |
|
46 |
+ SubDir: "openshift-deployer", |
|
47 |
+ User: "system:openshift-deployer", |
|
48 |
+ Groups: util.NewStringSet("system:deployers"), |
|
49 |
+ } |
|
50 |
+} |
|
51 |
+ |
|
52 |
+func DefaultOpenshiftLoopbackClientCertInfo(certDir string) ClientCertInfo { |
|
53 |
+ return ClientCertInfo{ |
|
54 |
+ CertLocation: configapi.CertInfo{ |
|
55 |
+ CertFile: DefaultCertFilename(certDir, "openshift-client"), |
|
56 |
+ KeyFile: DefaultKeyFilename(certDir, "openshift-client"), |
|
57 |
+ }, |
|
58 |
+ SubDir: "openshift-client", |
|
59 |
+ User: "system:openshift-client", |
|
60 |
+ } |
|
61 |
+} |
|
62 |
+ |
|
63 |
+func DefaultKubeClientClientCertInfo(certDir string) ClientCertInfo { |
|
64 |
+ return ClientCertInfo{ |
|
65 |
+ CertLocation: configapi.CertInfo{ |
|
66 |
+ CertFile: DefaultCertFilename(certDir, "kube-client"), |
|
67 |
+ KeyFile: DefaultKeyFilename(certDir, "kube-client"), |
|
68 |
+ }, |
|
69 |
+ SubDir: "kube-client", |
|
70 |
+ User: "system:kube-client", |
|
71 |
+ } |
|
72 |
+} |
|
73 |
+ |
|
74 |
+func DefaultClusterAdminClientCertInfo(certDir string) ClientCertInfo { |
|
75 |
+ return ClientCertInfo{ |
|
76 |
+ CertLocation: configapi.CertInfo{ |
|
77 |
+ CertFile: DefaultCertFilename(certDir, "admin"), |
|
78 |
+ KeyFile: DefaultKeyFilename(certDir, "admin"), |
|
79 |
+ }, |
|
80 |
+ SubDir: "admin", |
|
81 |
+ User: "system:admin", |
|
82 |
+ Groups: util.NewStringSet("system:cluster-admins"), |
|
83 |
+ } |
|
84 |
+} |
|
85 |
+ |
|
86 |
+func DefaultServerCerts(certDir string) []configapi.CertInfo { |
|
87 |
+ return []configapi.CertInfo{ |
|
88 |
+ DefaultMasterServingCertInfo(certDir), |
|
89 |
+ DefaultAssetServingCertInfo(certDir), |
|
90 |
+ } |
|
91 |
+} |
|
92 |
+ |
|
93 |
+func DefaultMasterServingCertInfo(certDir string) configapi.CertInfo { |
|
94 |
+ return configapi.CertInfo{ |
|
95 |
+ CertFile: DefaultCertFilename(certDir, "master"), |
|
96 |
+ KeyFile: DefaultKeyFilename(certDir, "master"), |
|
97 |
+ } |
|
98 |
+} |
|
99 |
+ |
|
100 |
+func DefaultNodeServingCertInfo(certDir, nodeName string) configapi.CertInfo { |
|
101 |
+ return configapi.CertInfo{ |
|
102 |
+ CertFile: DefaultCertFilename(certDir, "node_serving-"+nodeName), |
|
103 |
+ KeyFile: DefaultKeyFilename(certDir, "node_serving-"+nodeName), |
|
104 |
+ } |
|
105 |
+} |
|
106 |
+ |
|
107 |
+func DefaultAssetServingCertInfo(certDir string) configapi.CertInfo { |
|
108 |
+ return configapi.CertInfo{ |
|
109 |
+ CertFile: DefaultCertFilename(certDir, "master"), |
|
110 |
+ KeyFile: DefaultKeyFilename(certDir, "master"), |
|
111 |
+ } |
|
112 |
+} |
|
113 |
+ |
|
114 |
+func DefaultCertDir(certDir, username string) string { |
|
115 |
+ return path.Join(certDir, username) |
|
116 |
+} |
|
117 |
+ |
|
118 |
+func DefaultCertFilename(certDir, username string) string { |
|
119 |
+ return path.Join(DefaultCertDir(certDir, username), "cert.crt") |
|
120 |
+} |
|
121 |
+ |
|
122 |
+func DefaultKeyFilename(certDir, username string) string { |
|
123 |
+ return path.Join(DefaultCertDir(certDir, username), "key.key") |
|
124 |
+} |
|
125 |
+func DefaultSerialFilename(certDir, username string) string { |
|
126 |
+ return path.Join(DefaultCertDir(certDir, username), "serial.txt") |
|
127 |
+} |
|
128 |
+func DefaultKubeConfigFilename(certDir, username string) string { |
|
129 |
+ return path.Join(DefaultCertDir(certDir, username), ".kubeconfig") |
|
130 |
+} |
0 | 131 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,39 @@ |
0 |
+package certs |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ |
|
5 |
+ "github.com/spf13/pflag" |
|
6 |
+ |
|
7 |
+ "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+type GetSignerCertOptions struct { |
|
11 |
+ CertFile string |
|
12 |
+ KeyFile string |
|
13 |
+ SerialFile string |
|
14 |
+} |
|
15 |
+ |
|
16 |
+func BindGetSignerCertOptions(options *GetSignerCertOptions, flags *pflag.FlagSet, prefix string) { |
|
17 |
+ flags.StringVar(&options.CertFile, prefix+"signer-cert", "openshift.local.certificates/ca/cert.crt", "The certificate file.") |
|
18 |
+ flags.StringVar(&options.KeyFile, prefix+"signer-key", "openshift.local.certificates/ca/key.key", "The key file.") |
|
19 |
+ flags.StringVar(&options.SerialFile, prefix+"signer-serial", "openshift.local.certificates/ca/serial.txt", "The serial file that keeps track of how many certs have been signed.") |
|
20 |
+} |
|
21 |
+ |
|
22 |
+func (o GetSignerCertOptions) Validate() error { |
|
23 |
+ if len(o.CertFile) == 0 { |
|
24 |
+ return errors.New("signer-cert must be provided") |
|
25 |
+ } |
|
26 |
+ if len(o.KeyFile) == 0 { |
|
27 |
+ return errors.New("signer-key must be provided") |
|
28 |
+ } |
|
29 |
+ if len(o.SerialFile) == 0 { |
|
30 |
+ return errors.New("signer-serial must be provided") |
|
31 |
+ } |
|
32 |
+ |
|
33 |
+ return nil |
|
34 |
+} |
|
35 |
+ |
|
36 |
+func (o GetSignerCertOptions) GetSignerCert() (*crypto.CA, error) { |
|
37 |
+ return crypto.GetCA(o.CertFile, o.KeyFile, o.SerialFile) |
|
38 |
+} |
0 | 39 |
deleted file mode 100644 |
... | ... |
@@ -1,152 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "errors" |
|
5 |
- "fmt" |
|
6 |
- "net" |
|
7 |
- _ "net/http/pprof" |
|
8 |
- "strings" |
|
9 |
- |
|
10 |
- "github.com/golang/glog" |
|
11 |
- "github.com/spf13/cobra" |
|
12 |
- |
|
13 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
14 |
-) |
|
15 |
- |
|
16 |
-const longCommandDesc = ` |
|
17 |
-Start an OpenShift server |
|
18 |
- |
|
19 |
-This command helps you launch an OpenShift server. The default mode is all-in-one, which allows |
|
20 |
-you to run all of the components of an OpenShift system on a server with Docker. Running |
|
21 |
- |
|
22 |
- $ openshift start |
|
23 |
- |
|
24 |
-will start OpenShift listening on all interfaces, launch an etcd server to store persistent |
|
25 |
-data, and launch the Kubernetes system components. The server will run in the foreground until |
|
26 |
-you terminate the process. |
|
27 |
- |
|
28 |
-Note: starting OpenShift without passing the --master address will attempt to find the IP |
|
29 |
-address that will be visible inside running Docker containers. This is not always successful, |
|
30 |
-so if you have problems tell OpenShift what public address it will be via --master=<ip>. |
|
31 |
- |
|
32 |
-You may also pass an optional argument to the start command to start OpenShift in one of the |
|
33 |
-following roles: |
|
34 |
- |
|
35 |
- $ openshift start master --nodes=<host1,host2,host3,...> |
|
36 |
- |
|
37 |
- Launches the server and control plane for OpenShift. You may pass a list of the node |
|
38 |
- hostnames you want to use, or create nodes via the REST API or 'openshift kube'. |
|
39 |
- |
|
40 |
- $ openshift start node --master=<masterIP> |
|
41 |
- |
|
42 |
- Launches a new node and attempts to connect to the master on the provided IP. |
|
43 |
- |
|
44 |
-You may also pass --etcd=<address> to connect to an external etcd server instead of running an |
|
45 |
-integrated instance, or --kubernetes=<addr> and --kubeconfig=<path> to connect to an existing |
|
46 |
-Kubernetes cluster. |
|
47 |
-` |
|
48 |
- |
|
49 |
-// NewCommandStartServer provides a CLI handler for 'start' command |
|
50 |
-func NewCommandStartServer(name string) (*cobra.Command, *Config) { |
|
51 |
- cfg := NewDefaultConfig() |
|
52 |
- |
|
53 |
- cmd := &cobra.Command{ |
|
54 |
- Use: fmt.Sprintf("%s [master|node]", name), |
|
55 |
- Short: "Launch OpenShift", |
|
56 |
- Long: longCommandDesc, |
|
57 |
- Run: func(c *cobra.Command, args []string) { |
|
58 |
- if err := cfg.Validate(args); err != nil { |
|
59 |
- glog.Fatal(err) |
|
60 |
- } |
|
61 |
- |
|
62 |
- cfg.Complete(args) |
|
63 |
- |
|
64 |
- if err := cfg.Start(args); err != nil { |
|
65 |
- glog.Fatal(err) |
|
66 |
- } |
|
67 |
- }, |
|
68 |
- } |
|
69 |
- |
|
70 |
- flag := cmd.Flags() |
|
71 |
- |
|
72 |
- flag.BoolVar(&cfg.WriteConfigOnly, "config-only", false, "Indicates that the command should build the config that would be used to start OpenShift and do nothing else. This is not yet implemented.") |
|
73 |
- |
|
74 |
- flag.Var(&cfg.BindAddr, "listen", "The address to listen for connections on (host, host:port, or URL).") |
|
75 |
- flag.Var(&cfg.MasterAddr, "master", "The master address for use by OpenShift components (host, host:port, or URL). Scheme and port default to the --listen scheme and port.") |
|
76 |
- flag.Var(&cfg.MasterPublicAddr, "public-master", "The master address for use by public clients, if different (host, host:port, or URL). Defaults to same as --master.") |
|
77 |
- flag.Var(&cfg.EtcdAddr, "etcd", "The address of the etcd server (host, host:port, or URL). If specified, no built-in etcd will be started.") |
|
78 |
- flag.Var(&cfg.KubernetesAddr, "kubernetes", "The address of the Kubernetes server (host, host:port, or URL). If specified, no Kubernetes components will be started.") |
|
79 |
- flag.Var(&cfg.KubernetesPublicAddr, "public-kubernetes", "The Kubernetes server address for use by public clients, if different. (host, host:port, or URL). Defaults to same as --kubernetes.") |
|
80 |
- flag.Var(&cfg.PortalNet, "portal-net", "A CIDR notation IP range from which to assign portal IPs. This must not overlap with any IP ranges assigned to nodes for pods.") |
|
81 |
- |
|
82 |
- flag.StringVar(&cfg.ImageTemplate.Format, "images", cfg.ImageTemplate.Format, "When fetching images used by the cluster for important components, use this format on both master and nodes. The latest release will be used by default.") |
|
83 |
- flag.BoolVar(&cfg.ImageTemplate.Latest, "latest-images", cfg.ImageTemplate.Latest, "If true, attempt to use the latest images for the cluster instead of the latest release.") |
|
84 |
- |
|
85 |
- flag.StringVar(&cfg.VolumeDir, "volume-dir", "openshift.local.volumes", "The volume storage directory.") |
|
86 |
- flag.StringVar(&cfg.EtcdDir, "etcd-dir", "openshift.local.etcd", "The etcd data directory.") |
|
87 |
- flag.StringVar(&cfg.CertDir, "cert-dir", "openshift.local.certificates", "The certificate data directory.") |
|
88 |
- |
|
89 |
- flag.StringVar(&cfg.Hostname, "hostname", cfg.Hostname, "The hostname to identify this node with the master.") |
|
90 |
- flag.Var(&cfg.NodeList, "nodes", "The hostnames of each node. This currently must be specified up front. Comma delimited list") |
|
91 |
- flag.Var(&cfg.CORSAllowedOrigins, "cors-allowed-origins", "List of allowed origins for CORS, comma separated. An allowed origin can be a regular expression to support subdomain matching. CORS is enabled for localhost, 127.0.0.1, and the asset server by default.") |
|
92 |
- |
|
93 |
- flag.StringVar(&cfg.ClientConfigLoadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for requests to the Kubernetes API.") |
|
94 |
- |
|
95 |
- cfg.Docker.InstallFlags(flag) |
|
96 |
- |
|
97 |
- return cmd, cfg |
|
98 |
-} |
|
99 |
- |
|
100 |
-const startMaster = "master" |
|
101 |
-const startNode = "node" |
|
102 |
- |
|
103 |
-func (cfg Config) Validate(args []string) error { |
|
104 |
- switch len(args) { |
|
105 |
- case 1: |
|
106 |
- switch args[0] { |
|
107 |
- case startMaster: // allowed case |
|
108 |
- case startNode: // allowed case |
|
109 |
- default: |
|
110 |
- return errors.New("You may start an OpenShift all-in-one server with no arguments, or pass 'master' or 'node' to run in that role.") |
|
111 |
- } |
|
112 |
- case 0: |
|
113 |
- // do nothing, this starts an all in one |
|
114 |
- |
|
115 |
- default: |
|
116 |
- return errors.New("You may start an OpenShift all-in-one server with no arguments, or pass 'master' or 'node' to run in that role.") |
|
117 |
- } |
|
118 |
- |
|
119 |
- return nil |
|
120 |
-} |
|
121 |
- |
|
122 |
-// Complete takes the args and fills in information for the start config |
|
123 |
-func (cfg *Config) Complete(args []string) { |
|
124 |
- cfg.StartMaster = (len(args) == 0) || (args[0] == startMaster) |
|
125 |
- cfg.StartNode = (len(args) == 0) || (args[0] == startNode) |
|
126 |
- |
|
127 |
- if cfg.StartMaster { |
|
128 |
- // if we've explicitly called out a kube server or a client config, don't start kube in-process |
|
129 |
- cfg.StartKube = !cfg.KubernetesAddr.Provided && len(cfg.ClientConfigLoadingRules.CommandLinePath) == 0 |
|
130 |
- // if we've explicitly called out an etcd server, don't start etcd in-process |
|
131 |
- cfg.StartEtcd = !cfg.EtcdAddr.Provided |
|
132 |
- } |
|
133 |
- |
|
134 |
- // if this is an all-in-one start, be sure to add our hostname to the NodeList if it is not already present |
|
135 |
- isAllInOne := (len(args) == 0) |
|
136 |
- if isAllInOne { |
|
137 |
- nodeList := util.NewStringSet(strings.ToLower(cfg.Hostname)) |
|
138 |
- // take everything toLower |
|
139 |
- for _, s := range cfg.NodeList { |
|
140 |
- nodeList.Insert(strings.ToLower(s)) |
|
141 |
- } |
|
142 |
- |
|
143 |
- cfg.NodeList = nodeList.List() |
|
144 |
- |
|
145 |
- // in the all-in-one, default ClusterDNS to the master's address |
|
146 |
- if url, err := cfg.GetMasterAddress(); err == nil { |
|
147 |
- if host, _, err := net.SplitHostPort(url.Host); err == nil { |
|
148 |
- cfg.ClusterDNS = net.ParseIP(host) |
|
149 |
- } |
|
150 |
- } |
|
151 |
- } |
|
152 |
-} |
153 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,364 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "strconv" |
|
5 |
- "strings" |
|
6 |
- "testing" |
|
7 |
- |
|
8 |
- "github.com/spf13/cobra" |
|
9 |
- |
|
10 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
11 |
-) |
|
12 |
- |
|
13 |
-func TestCommandBindingListen(t *testing.T) { |
|
14 |
- valueToSet := "http://example.org:9123" |
|
15 |
- actualCfg := executeCommand([]string{"--listen=" + valueToSet}) |
|
16 |
- |
|
17 |
- expectedConfig := NewDefaultConfig() |
|
18 |
- expectedConfig.BindAddr.Set(valueToSet) |
|
19 |
- |
|
20 |
- if expectedConfig.BindAddr.String() != actualCfg.BindAddr.String() { |
|
21 |
- t.Errorf("expected %v, got %v", expectedConfig.BindAddr.String(), actualCfg.BindAddr.String()) |
|
22 |
- } |
|
23 |
-} |
|
24 |
- |
|
25 |
-func TestCommandBindingMaster(t *testing.T) { |
|
26 |
- valueToSet := "http://example.org:9123" |
|
27 |
- actualCfg := executeCommand([]string{"--master=" + valueToSet}) |
|
28 |
- |
|
29 |
- expectedConfig := NewDefaultConfig() |
|
30 |
- expectedConfig.MasterAddr.Set(valueToSet) |
|
31 |
- |
|
32 |
- if expectedConfig.MasterAddr.String() != actualCfg.MasterAddr.String() { |
|
33 |
- t.Errorf("expected %v, got %v", expectedConfig.MasterAddr.String(), actualCfg.MasterAddr.String()) |
|
34 |
- } |
|
35 |
-} |
|
36 |
- |
|
37 |
-func TestCommandBindingMasterPublic(t *testing.T) { |
|
38 |
- valueToSet := "http://example.org:9123" |
|
39 |
- actualCfg := executeCommand([]string{"--public-master=" + valueToSet}) |
|
40 |
- |
|
41 |
- expectedConfig := NewDefaultConfig() |
|
42 |
- expectedConfig.MasterPublicAddr.Set(valueToSet) |
|
43 |
- |
|
44 |
- if expectedConfig.MasterPublicAddr.String() != actualCfg.MasterPublicAddr.String() { |
|
45 |
- t.Errorf("expected %v, got %v", expectedConfig.MasterPublicAddr.String(), actualCfg.MasterPublicAddr.String()) |
|
46 |
- } |
|
47 |
-} |
|
48 |
- |
|
49 |
-func TestCommandBindingEtcd(t *testing.T) { |
|
50 |
- valueToSet := "http://example.org:9123" |
|
51 |
- actualCfg := executeCommand([]string{"--etcd=" + valueToSet}) |
|
52 |
- |
|
53 |
- expectedConfig := NewDefaultConfig() |
|
54 |
- expectedConfig.EtcdAddr.Set(valueToSet) |
|
55 |
- |
|
56 |
- if expectedConfig.EtcdAddr.String() != actualCfg.EtcdAddr.String() { |
|
57 |
- t.Errorf("expected %v, got %v", expectedConfig.EtcdAddr.String(), actualCfg.EtcdAddr.String()) |
|
58 |
- } |
|
59 |
-} |
|
60 |
- |
|
61 |
-func TestCommandBindingKubernetes(t *testing.T) { |
|
62 |
- valueToSet := "http://example.org:9123" |
|
63 |
- actualCfg := executeCommand([]string{"--kubernetes=" + valueToSet}) |
|
64 |
- |
|
65 |
- expectedConfig := NewDefaultConfig() |
|
66 |
- expectedConfig.KubernetesAddr.Set(valueToSet) |
|
67 |
- |
|
68 |
- if expectedConfig.KubernetesAddr.String() != actualCfg.KubernetesAddr.String() { |
|
69 |
- t.Errorf("expected %v, got %v", expectedConfig.KubernetesAddr.String(), actualCfg.KubernetesAddr.String()) |
|
70 |
- } |
|
71 |
-} |
|
72 |
- |
|
73 |
-func TestCommandBindingKubernetesPublic(t *testing.T) { |
|
74 |
- valueToSet := "http://example.org:9123" |
|
75 |
- actualCfg := executeCommand([]string{"--public-kubernetes=" + valueToSet}) |
|
76 |
- |
|
77 |
- expectedConfig := NewDefaultConfig() |
|
78 |
- expectedConfig.KubernetesPublicAddr.Set(valueToSet) |
|
79 |
- |
|
80 |
- if expectedConfig.KubernetesPublicAddr.String() != actualCfg.KubernetesPublicAddr.String() { |
|
81 |
- t.Errorf("expected %v, got %v", expectedConfig.KubernetesPublicAddr.String(), actualCfg.KubernetesPublicAddr.String()) |
|
82 |
- } |
|
83 |
-} |
|
84 |
- |
|
85 |
-func TestCommandBindingPortalNet(t *testing.T) { |
|
86 |
- valueToSet := "192.168.0.0/16" |
|
87 |
- actualCfg := executeCommand([]string{"--portal-net=" + valueToSet}) |
|
88 |
- |
|
89 |
- expectedConfig := NewDefaultConfig() |
|
90 |
- expectedConfig.PortalNet.Set(valueToSet) |
|
91 |
- |
|
92 |
- if expectedConfig.PortalNet.String() != actualCfg.PortalNet.String() { |
|
93 |
- t.Errorf("expected %v, got %v", expectedConfig.PortalNet.String(), actualCfg.PortalNet.String()) |
|
94 |
- } |
|
95 |
-} |
|
96 |
- |
|
97 |
-func TestCommandBindingImageTemplateFormat(t *testing.T) { |
|
98 |
- valueToSet := "some-format-string" |
|
99 |
- actualCfg := executeCommand([]string{"--images=" + valueToSet}) |
|
100 |
- |
|
101 |
- expectedConfig := NewDefaultConfig() |
|
102 |
- expectedConfig.ImageTemplate.Format = valueToSet |
|
103 |
- |
|
104 |
- if expectedConfig.ImageTemplate.Format != actualCfg.ImageTemplate.Format { |
|
105 |
- t.Errorf("expected %v, got %v", expectedConfig.ImageTemplate.Format, actualCfg.ImageTemplate.Format) |
|
106 |
- } |
|
107 |
-} |
|
108 |
- |
|
109 |
-func TestCommandBindingImageLatest(t *testing.T) { |
|
110 |
- expectedConfig := NewDefaultConfig() |
|
111 |
- |
|
112 |
- valueToSet := strconv.FormatBool(!expectedConfig.ImageTemplate.Latest) |
|
113 |
- actualCfg := executeCommand([]string{"--latest-images=" + valueToSet}) |
|
114 |
- |
|
115 |
- expectedConfig.ImageTemplate.Latest = !expectedConfig.ImageTemplate.Latest |
|
116 |
- |
|
117 |
- if expectedConfig.ImageTemplate.Latest != actualCfg.ImageTemplate.Latest { |
|
118 |
- t.Errorf("expected %v, got %v", expectedConfig.ImageTemplate.Latest, actualCfg.ImageTemplate.Latest) |
|
119 |
- } |
|
120 |
-} |
|
121 |
- |
|
122 |
-func TestCommandBindingVolumeDir(t *testing.T) { |
|
123 |
- valueToSet := "some-string" |
|
124 |
- actualCfg := executeCommand([]string{"--volume-dir=" + valueToSet}) |
|
125 |
- |
|
126 |
- expectedConfig := NewDefaultConfig() |
|
127 |
- expectedConfig.VolumeDir = valueToSet |
|
128 |
- |
|
129 |
- if expectedConfig.VolumeDir != actualCfg.VolumeDir { |
|
130 |
- t.Errorf("expected %v, got %v", expectedConfig.VolumeDir, actualCfg.VolumeDir) |
|
131 |
- } |
|
132 |
-} |
|
133 |
- |
|
134 |
-func TestCommandBindingEtcdDir(t *testing.T) { |
|
135 |
- valueToSet := "some-string" |
|
136 |
- actualCfg := executeCommand([]string{"--etcd-dir=" + valueToSet}) |
|
137 |
- |
|
138 |
- expectedConfig := NewDefaultConfig() |
|
139 |
- expectedConfig.EtcdDir = valueToSet |
|
140 |
- |
|
141 |
- if expectedConfig.EtcdDir != actualCfg.EtcdDir { |
|
142 |
- t.Errorf("expected %v, got %v", expectedConfig.EtcdDir, actualCfg.EtcdDir) |
|
143 |
- } |
|
144 |
-} |
|
145 |
- |
|
146 |
-func TestCommandBindingCertDir(t *testing.T) { |
|
147 |
- valueToSet := "some-string" |
|
148 |
- actualCfg := executeCommand([]string{"--cert-dir=" + valueToSet}) |
|
149 |
- |
|
150 |
- expectedConfig := NewDefaultConfig() |
|
151 |
- expectedConfig.CertDir = valueToSet |
|
152 |
- |
|
153 |
- if expectedConfig.CertDir != actualCfg.CertDir { |
|
154 |
- t.Errorf("expected %v, got %v", expectedConfig.CertDir, actualCfg.CertDir) |
|
155 |
- } |
|
156 |
-} |
|
157 |
- |
|
158 |
-func TestCommandBindingHostname(t *testing.T) { |
|
159 |
- valueToSet := "some-string" |
|
160 |
- actualCfg := executeCommand([]string{"--hostname=" + valueToSet}) |
|
161 |
- |
|
162 |
- expectedConfig := NewDefaultConfig() |
|
163 |
- expectedConfig.Hostname = valueToSet |
|
164 |
- |
|
165 |
- if expectedConfig.Hostname != actualCfg.Hostname { |
|
166 |
- t.Errorf("expected %v, got %v", expectedConfig.Hostname, actualCfg.Hostname) |
|
167 |
- } |
|
168 |
-} |
|
169 |
- |
|
170 |
-// AllInOne always adds the default hostname |
|
171 |
-func TestCommandBindingNodesForAllInOneAppend(t *testing.T) { |
|
172 |
- valueToSet := "first,second,third" |
|
173 |
- actualCfg := executeCommand([]string{"--nodes=" + valueToSet}) |
|
174 |
- |
|
175 |
- expectedConfig := NewDefaultConfig() |
|
176 |
- |
|
177 |
- stringList := util.StringList{} |
|
178 |
- stringList.Set(valueToSet + "," + strings.ToLower(expectedConfig.Hostname)) |
|
179 |
- expectedConfig.NodeList.Set(strings.Join(util.NewStringSet(stringList...).List(), ",")) |
|
180 |
- |
|
181 |
- if expectedConfig.NodeList.String() != actualCfg.NodeList.String() { |
|
182 |
- t.Errorf("expected %v, got %v", expectedConfig.NodeList, actualCfg.NodeList) |
|
183 |
- } |
|
184 |
-} |
|
185 |
- |
|
186 |
-// AllInOne always adds the default hostname |
|
187 |
-func TestCommandBindingNodesForAllInOneAppendNoDupes(t *testing.T) { |
|
188 |
- |
|
189 |
- valueToSet := "first,localhost,second,third" |
|
190 |
- actualCfg := executeCommand([]string{"--nodes=" + valueToSet, "--hostname=LOCALHOST"}) |
|
191 |
- |
|
192 |
- expectedConfig := NewDefaultConfig() |
|
193 |
- expectedConfig.NodeList.Set(valueToSet) |
|
194 |
- |
|
195 |
- util.NewStringSet() |
|
196 |
- |
|
197 |
- if expectedConfig.NodeList.String() != actualCfg.NodeList.String() { |
|
198 |
- t.Errorf("expected %v, got %v", expectedConfig.NodeList, actualCfg.NodeList) |
|
199 |
- } |
|
200 |
-} |
|
201 |
- |
|
202 |
-// AllInOne always adds the default hostname |
|
203 |
-func TestCommandBindingNodesDefaultingAllInOne(t *testing.T) { |
|
204 |
- actualCfg := executeCommand([]string{}) |
|
205 |
- |
|
206 |
- expectedConfig := NewDefaultConfig() |
|
207 |
- expectedConfig.NodeList.Set(strings.ToLower(expectedConfig.Hostname)) |
|
208 |
- |
|
209 |
- if expectedConfig.NodeList.String() != actualCfg.NodeList.String() { |
|
210 |
- t.Errorf("expected %v, got %v", expectedConfig.NodeList, actualCfg.NodeList) |
|
211 |
- } |
|
212 |
-} |
|
213 |
- |
|
214 |
-// explicit start master never modifies the NodeList |
|
215 |
-func TestCommandBindingNodesForMaster(t *testing.T) { |
|
216 |
- valueToSet := "first,second,third" |
|
217 |
- actualCfg := executeCommand([]string{"master", "--nodes=" + valueToSet}) |
|
218 |
- |
|
219 |
- expectedConfig := NewDefaultConfig() |
|
220 |
- expectedConfig.NodeList.Set(valueToSet) |
|
221 |
- |
|
222 |
- if expectedConfig.NodeList.String() != actualCfg.NodeList.String() { |
|
223 |
- t.Errorf("expected %v, got %v", expectedConfig.NodeList, actualCfg.NodeList) |
|
224 |
- } |
|
225 |
-} |
|
226 |
- |
|
227 |
-// explicit start master never modifies the NodeList |
|
228 |
-func TestCommandBindingNodesDefaultingMaster(t *testing.T) { |
|
229 |
- actualCfg := executeCommand([]string{"master"}) |
|
230 |
- |
|
231 |
- expectedConfig := NewDefaultConfig() |
|
232 |
- expectedConfig.NodeList.Set("") |
|
233 |
- |
|
234 |
- if expectedConfig.NodeList.String() != actualCfg.NodeList.String() { |
|
235 |
- t.Errorf("expected %v, got %v", expectedConfig.NodeList, actualCfg.NodeList) |
|
236 |
- } |
|
237 |
-} |
|
238 |
- |
|
239 |
-func TestCommandBindingCors(t *testing.T) { |
|
240 |
- valueToSet := "first,second,third" |
|
241 |
- actualCfg := executeCommand([]string{"--cors-allowed-origins=" + valueToSet}) |
|
242 |
- |
|
243 |
- expectedConfig := NewDefaultConfig() |
|
244 |
- expectedConfig.CORSAllowedOrigins.Set(valueToSet) |
|
245 |
- |
|
246 |
- if expectedConfig.CORSAllowedOrigins.String() != actualCfg.CORSAllowedOrigins.String() { |
|
247 |
- t.Errorf("expected %v, got %v", expectedConfig.CORSAllowedOrigins, actualCfg.CORSAllowedOrigins) |
|
248 |
- } |
|
249 |
-} |
|
250 |
- |
|
251 |
-func TestCommandCompletionNode(t *testing.T) { |
|
252 |
- commandCompletionTest{ |
|
253 |
- args: []string{"node"}, |
|
254 |
- |
|
255 |
- StartNode: true, |
|
256 |
- }.run(t) |
|
257 |
-} |
|
258 |
- |
|
259 |
-func TestCommandCompletionMaster(t *testing.T) { |
|
260 |
- commandCompletionTest{ |
|
261 |
- args: []string{"master"}, |
|
262 |
- |
|
263 |
- StartMaster: true, |
|
264 |
- StartKube: true, |
|
265 |
- StartEtcd: true, |
|
266 |
- }.run(t) |
|
267 |
-} |
|
268 |
-func TestCommandCompletionMasterExternalKubernetes(t *testing.T) { |
|
269 |
- commandCompletionTest{ |
|
270 |
- args: []string{"master", "--kubernetes=foo"}, |
|
271 |
- |
|
272 |
- StartMaster: true, |
|
273 |
- StartKube: false, |
|
274 |
- StartEtcd: true, |
|
275 |
- }.run(t) |
|
276 |
-} |
|
277 |
-func TestCommandCompletionMasterExternalKubernetesConfig(t *testing.T) { |
|
278 |
- commandCompletionTest{ |
|
279 |
- args: []string{"master", "--kubeconfig=foo"}, |
|
280 |
- |
|
281 |
- StartMaster: true, |
|
282 |
- StartKube: false, |
|
283 |
- StartEtcd: true, |
|
284 |
- }.run(t) |
|
285 |
-} |
|
286 |
- |
|
287 |
-func TestCommandCompletionAllInOne(t *testing.T) { |
|
288 |
- commandCompletionTest{ |
|
289 |
- StartNode: true, |
|
290 |
- StartMaster: true, |
|
291 |
- StartKube: true, |
|
292 |
- StartEtcd: true, |
|
293 |
- }.run(t) |
|
294 |
-} |
|
295 |
-func TestCommandCompletionAllInOneExternalKubernetes(t *testing.T) { |
|
296 |
- commandCompletionTest{ |
|
297 |
- args: []string{"--kubernetes=foo"}, |
|
298 |
- |
|
299 |
- StartNode: true, |
|
300 |
- StartMaster: true, |
|
301 |
- StartKube: false, |
|
302 |
- StartEtcd: true, |
|
303 |
- }.run(t) |
|
304 |
-} |
|
305 |
-func TestCommandCompletionAllInOneExternalKubernetesConfig(t *testing.T) { |
|
306 |
- commandCompletionTest{ |
|
307 |
- args: []string{"--kubeconfig=foo"}, |
|
308 |
- |
|
309 |
- StartNode: true, |
|
310 |
- StartMaster: true, |
|
311 |
- StartKube: false, |
|
312 |
- StartEtcd: true, |
|
313 |
- }.run(t) |
|
314 |
-} |
|
315 |
- |
|
316 |
-type commandCompletionTest struct { |
|
317 |
- args []string |
|
318 |
- |
|
319 |
- StartNode bool |
|
320 |
- StartMaster bool |
|
321 |
- StartKube bool |
|
322 |
- StartEtcd bool |
|
323 |
-} |
|
324 |
- |
|
325 |
-func executeCommand(args []string) *Config { |
|
326 |
- argsToUse := make([]string, 0, 1+len(args)) |
|
327 |
- argsToUse = append(argsToUse, "start") |
|
328 |
- argsToUse = append(argsToUse, args...) |
|
329 |
- argsToUse = append(argsToUse, "--config-only") |
|
330 |
- |
|
331 |
- root := &cobra.Command{ |
|
332 |
- Use: "openshift", |
|
333 |
- Short: "test", |
|
334 |
- Long: "", |
|
335 |
- Run: func(c *cobra.Command, args []string) { |
|
336 |
- c.Help() |
|
337 |
- }, |
|
338 |
- } |
|
339 |
- |
|
340 |
- openshiftStartCommand, cfg := NewCommandStartServer("start") |
|
341 |
- root.AddCommand(openshiftStartCommand) |
|
342 |
- root.SetArgs(argsToUse) |
|
343 |
- root.Execute() |
|
344 |
- |
|
345 |
- return cfg |
|
346 |
-} |
|
347 |
- |
|
348 |
-func (test commandCompletionTest) run(t *testing.T) { |
|
349 |
- actualCfg := executeCommand(test.args) |
|
350 |
- |
|
351 |
- if test.StartNode != actualCfg.StartNode { |
|
352 |
- t.Errorf("expected %v, got %v", test.StartNode, actualCfg.StartNode) |
|
353 |
- } |
|
354 |
- if test.StartMaster != actualCfg.StartMaster { |
|
355 |
- t.Errorf("expected %v, got %v", test.StartMaster, actualCfg.StartMaster) |
|
356 |
- } |
|
357 |
- if test.StartKube != actualCfg.StartKube { |
|
358 |
- t.Errorf("expected %v, got %v", test.StartKube, actualCfg.StartKube) |
|
359 |
- } |
|
360 |
- if test.StartEtcd != actualCfg.StartEtcd { |
|
361 |
- t.Errorf("expected %v, got %v", test.StartEtcd, actualCfg.StartEtcd) |
|
362 |
- } |
|
363 |
- |
|
364 |
-} |
365 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,303 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "net" |
|
6 |
- "net/url" |
|
7 |
- "os/exec" |
|
8 |
- "strconv" |
|
9 |
- "strings" |
|
10 |
- "time" |
|
11 |
- |
|
12 |
- etcdclient "github.com/coreos/go-etcd/etcd" |
|
13 |
- "github.com/golang/glog" |
|
14 |
- |
|
15 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
16 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
17 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
18 |
- kutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
19 |
- |
|
20 |
- "github.com/openshift/origin/pkg/api/latest" |
|
21 |
- "github.com/openshift/origin/pkg/cmd/flagtypes" |
|
22 |
- "github.com/openshift/origin/pkg/cmd/util" |
|
23 |
- "github.com/openshift/origin/pkg/cmd/util/docker" |
|
24 |
- "github.com/openshift/origin/pkg/cmd/util/variable" |
|
25 |
-) |
|
26 |
- |
|
27 |
-// Config is a struct that the command stores flag values into. |
|
28 |
-type Config struct { |
|
29 |
- Docker *docker.Helper |
|
30 |
- |
|
31 |
- WriteConfigOnly bool |
|
32 |
- |
|
33 |
- StartNode bool |
|
34 |
- StartMaster bool |
|
35 |
- StartKube bool |
|
36 |
- StartEtcd bool |
|
37 |
- |
|
38 |
- MasterAddr flagtypes.Addr |
|
39 |
- BindAddr flagtypes.Addr |
|
40 |
- EtcdAddr flagtypes.Addr |
|
41 |
- KubernetesAddr flagtypes.Addr |
|
42 |
- PortalNet flagtypes.IPNet |
|
43 |
- DNSBindAddr flagtypes.Addr |
|
44 |
- // addresses for external clients |
|
45 |
- MasterPublicAddr flagtypes.Addr |
|
46 |
- KubernetesPublicAddr flagtypes.Addr |
|
47 |
- // addresses for asset server |
|
48 |
- AssetBindAddr flagtypes.Addr |
|
49 |
- AssetPublicAddr flagtypes.Addr |
|
50 |
- |
|
51 |
- ImageTemplate variable.ImageTemplate |
|
52 |
- |
|
53 |
- Hostname string |
|
54 |
- VolumeDir string |
|
55 |
- |
|
56 |
- EtcdDir string |
|
57 |
- |
|
58 |
- CertDir string |
|
59 |
- |
|
60 |
- ClusterDNS net.IP |
|
61 |
- |
|
62 |
- StorageVersion string |
|
63 |
- |
|
64 |
- NodeList kutil.StringList |
|
65 |
- |
|
66 |
- // ClientConfig is used when connecting to Kubernetes from the master, or |
|
67 |
- // when connecting to the master from a detached node. If StartKube is true, |
|
68 |
- // this value is not used. |
|
69 |
- ClientConfig clientcmd.ClientConfig |
|
70 |
- // ClientConfigLoadingRules is the ruleset used to load the client config. |
|
71 |
- // Only the CommandLinePath is expected to be used. |
|
72 |
- ClientConfigLoadingRules clientcmd.ClientConfigLoadingRules |
|
73 |
- |
|
74 |
- CORSAllowedOrigins kutil.StringList |
|
75 |
-} |
|
76 |
- |
|
77 |
-func NewDefaultConfig() *Config { |
|
78 |
- hostname, err := defaultHostname() |
|
79 |
- if err != nil { |
|
80 |
- hostname = "localhost" |
|
81 |
- glog.Warningf("Unable to lookup hostname, using %q: %v", hostname, err) |
|
82 |
- } |
|
83 |
- |
|
84 |
- // TODO: secure etcd by default |
|
85 |
- |
|
86 |
- config := &Config{ |
|
87 |
- Docker: docker.NewHelper(), |
|
88 |
- |
|
89 |
- MasterAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
90 |
- BindAddr: flagtypes.Addr{Value: "0.0.0.0:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
91 |
- EtcdAddr: flagtypes.Addr{Value: "0.0.0.0:4001", DefaultScheme: "http", DefaultPort: 4001}.Default(), |
|
92 |
- KubernetesAddr: flagtypes.Addr{DefaultScheme: "https", DefaultPort: 8443}.Default(), |
|
93 |
- PortalNet: flagtypes.DefaultIPNet("172.30.17.0/24"), |
|
94 |
- MasterPublicAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
95 |
- KubernetesPublicAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
96 |
- AssetPublicAddr: flagtypes.Addr{Value: "localhost:8444", DefaultScheme: "https", DefaultPort: 8444, AllowPrefix: true}.Default(), |
|
97 |
- AssetBindAddr: flagtypes.Addr{Value: "0.0.0.0:8444", DefaultScheme: "https", DefaultPort: 8444, AllowPrefix: true}.Default(), |
|
98 |
- |
|
99 |
- ImageTemplate: variable.NewDefaultImageTemplate(), |
|
100 |
- |
|
101 |
- Hostname: hostname, |
|
102 |
- } |
|
103 |
- |
|
104 |
- // TODO: allow DNS binding to be disabled. |
|
105 |
- config.DNSBindAddr = flagtypes.Addr{Value: config.BindAddr.Host, DefaultPort: 53}.Default() |
|
106 |
- |
|
107 |
- config.ClientConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&config.ClientConfigLoadingRules, &clientcmd.ConfigOverrides{}) |
|
108 |
- |
|
109 |
- return config |
|
110 |
-} |
|
111 |
- |
|
112 |
-// GetMasterAddress checks for an unset master address and then attempts to use the first |
|
113 |
-// public IPv4 non-loopback address registered on this host. |
|
114 |
-// TODO: make me IPv6 safe |
|
115 |
-func (cfg Config) GetMasterAddress() (*url.URL, error) { |
|
116 |
- if cfg.MasterAddr.Provided { |
|
117 |
- return cfg.MasterAddr.URL, nil |
|
118 |
- } |
|
119 |
- |
|
120 |
- // If the user specifies a bind address, and the master is not provided, use the bind port by default |
|
121 |
- port := cfg.MasterAddr.Port |
|
122 |
- if cfg.BindAddr.Provided { |
|
123 |
- port = cfg.BindAddr.Port |
|
124 |
- } |
|
125 |
- |
|
126 |
- // If the user specifies a bind address, and the master is not provided, use the bind scheme by default |
|
127 |
- scheme := cfg.MasterAddr.URL.Scheme |
|
128 |
- if cfg.BindAddr.Provided { |
|
129 |
- scheme = cfg.BindAddr.URL.Scheme |
|
130 |
- } |
|
131 |
- |
|
132 |
- // use the default ip address for the system |
|
133 |
- addr := "" |
|
134 |
- if ip, err := util.DefaultLocalIP4(); err == nil { |
|
135 |
- addr = ip.String() |
|
136 |
- } else if err == util.ErrorNoDefaultIP { |
|
137 |
- addr = "127.0.0.1" |
|
138 |
- } else if err != nil { |
|
139 |
- return nil, fmt.Errorf("Unable to find a public IP address: %v", err) |
|
140 |
- } |
|
141 |
- |
|
142 |
- masterAddr := scheme + "://" + net.JoinHostPort(addr, strconv.Itoa(port)) |
|
143 |
- return url.Parse(masterAddr) |
|
144 |
-} |
|
145 |
- |
|
146 |
-func (cfg Config) GetMasterPublicAddress() (*url.URL, error) { |
|
147 |
- if cfg.MasterPublicAddr.Provided { |
|
148 |
- return cfg.MasterPublicAddr.URL, nil |
|
149 |
- } |
|
150 |
- |
|
151 |
- return cfg.GetMasterAddress() |
|
152 |
-} |
|
153 |
- |
|
154 |
-func (cfg Config) GetEtcdBindAddress() string { |
|
155 |
- // Derive the etcd bind address by using the bind address and the default etcd port |
|
156 |
- return net.JoinHostPort(cfg.BindAddr.Host, strconv.Itoa(cfg.EtcdAddr.DefaultPort)) |
|
157 |
-} |
|
158 |
- |
|
159 |
-func (cfg Config) GetEtcdPeerBindAddress() string { |
|
160 |
- // Derive the etcd peer address by using the bind address and the default etcd peering port |
|
161 |
- return net.JoinHostPort(cfg.BindAddr.Host, "7001") |
|
162 |
-} |
|
163 |
- |
|
164 |
-func (cfg Config) GetEtcdAddress() (*url.URL, error) { |
|
165 |
- if cfg.EtcdAddr.Provided { |
|
166 |
- return cfg.EtcdAddr.URL, nil |
|
167 |
- } |
|
168 |
- |
|
169 |
- // Etcd should be reachable on the same address that the master is (for simplicity) |
|
170 |
- masterAddr, err := cfg.GetMasterAddress() |
|
171 |
- if err != nil { |
|
172 |
- return nil, err |
|
173 |
- } |
|
174 |
- |
|
175 |
- etcdAddr := net.JoinHostPort(getHost(*masterAddr), strconv.Itoa(cfg.EtcdAddr.DefaultPort)) |
|
176 |
- return url.Parse(cfg.EtcdAddr.DefaultScheme + "://" + etcdAddr) |
|
177 |
-} |
|
178 |
- |
|
179 |
-func (cfg Config) GetExternalKubernetesClientConfig() (*client.Config, bool, error) { |
|
180 |
- if len(cfg.ClientConfigLoadingRules.CommandLinePath) == 0 || cfg.ClientConfig == nil { |
|
181 |
- return nil, false, nil |
|
182 |
- } |
|
183 |
- clientConfig, err := cfg.ClientConfig.ClientConfig() |
|
184 |
- if err != nil { |
|
185 |
- return nil, false, err |
|
186 |
- } |
|
187 |
- return clientConfig, true, nil |
|
188 |
-} |
|
189 |
- |
|
190 |
-func (cfg Config) GetKubernetesAddress() (*url.URL, error) { |
|
191 |
- if cfg.KubernetesAddr.Provided { |
|
192 |
- return cfg.KubernetesAddr.URL, nil |
|
193 |
- } |
|
194 |
- |
|
195 |
- config, ok, err := cfg.GetExternalKubernetesClientConfig() |
|
196 |
- if err != nil { |
|
197 |
- return nil, err |
|
198 |
- } |
|
199 |
- if ok && len(config.Host) > 0 { |
|
200 |
- return url.Parse(config.Host) |
|
201 |
- } |
|
202 |
- |
|
203 |
- return cfg.GetMasterAddress() |
|
204 |
-} |
|
205 |
- |
|
206 |
-func (cfg Config) GetKubernetesPublicAddress() (*url.URL, error) { |
|
207 |
- if cfg.KubernetesPublicAddr.Provided { |
|
208 |
- return cfg.KubernetesPublicAddr.URL, nil |
|
209 |
- } |
|
210 |
- if cfg.KubernetesAddr.Provided { |
|
211 |
- return cfg.KubernetesAddr.URL, nil |
|
212 |
- } |
|
213 |
- config, ok, err := cfg.GetExternalKubernetesClientConfig() |
|
214 |
- if err != nil { |
|
215 |
- return nil, err |
|
216 |
- } |
|
217 |
- if ok && len(config.Host) > 0 { |
|
218 |
- return url.Parse(config.Host) |
|
219 |
- } |
|
220 |
- |
|
221 |
- return cfg.GetMasterPublicAddress() |
|
222 |
-} |
|
223 |
- |
|
224 |
-func (cfg Config) GetAssetPublicAddress() (*url.URL, error) { |
|
225 |
- if cfg.AssetPublicAddr.Provided { |
|
226 |
- return cfg.AssetPublicAddr.URL, nil |
|
227 |
- } |
|
228 |
- // Derive the asset public address by incrementing the master public address port by 1 |
|
229 |
- // TODO: derive the scheme/port from the asset bind scheme/port once that is settable via the command line |
|
230 |
- t, err := cfg.GetMasterPublicAddress() |
|
231 |
- if err != nil { |
|
232 |
- return nil, err |
|
233 |
- } |
|
234 |
- assetPublicAddr := *t |
|
235 |
- assetPublicAddr.Host = net.JoinHostPort(getHost(assetPublicAddr), strconv.Itoa(getPort(assetPublicAddr)+1)) |
|
236 |
- |
|
237 |
- return &assetPublicAddr, nil |
|
238 |
-} |
|
239 |
- |
|
240 |
-func (cfg Config) GetAssetBindAddress() string { |
|
241 |
- if cfg.AssetBindAddr.Provided { |
|
242 |
- return cfg.AssetBindAddr.URL.Host |
|
243 |
- } |
|
244 |
- // Derive the asset bind address by incrementing the master bind address port by 1 |
|
245 |
- return net.JoinHostPort(cfg.BindAddr.Host, strconv.Itoa(cfg.BindAddr.Port+1)) |
|
246 |
-} |
|
247 |
- |
|
248 |
-// getAndTestEtcdClient creates an etcd client based on the provided config and waits |
|
249 |
-// until etcd server is reachable. It errors out and exits if the server cannot |
|
250 |
-// be reached for a certain amount of time. |
|
251 |
-func (cfg Config) getAndTestEtcdClient() (*etcdclient.Client, error) { |
|
252 |
- address, err := cfg.GetEtcdAddress() |
|
253 |
- if err != nil { |
|
254 |
- return nil, err |
|
255 |
- } |
|
256 |
- etcdServers := []string{address.String()} |
|
257 |
- etcdClient := etcdclient.NewClient(etcdServers) |
|
258 |
- |
|
259 |
- for i := 0; ; i++ { |
|
260 |
- // TODO: make sure this works with etcd2 (root key may not exist) |
|
261 |
- _, err := etcdClient.Get("/", false, false) |
|
262 |
- if err == nil || tools.IsEtcdNotFound(err) { |
|
263 |
- break |
|
264 |
- } |
|
265 |
- if i > 100 { |
|
266 |
- return nil, fmt.Errorf("Could not reach etcd: %v", err) |
|
267 |
- } |
|
268 |
- time.Sleep(50 * time.Millisecond) |
|
269 |
- } |
|
270 |
- |
|
271 |
- return etcdClient, nil |
|
272 |
-} |
|
273 |
- |
|
274 |
-// newOpenShiftEtcdHelper returns an EtcdHelper for the provided arguments or an error if the version |
|
275 |
-// is incorrect. |
|
276 |
-func (cfg Config) newOpenShiftEtcdHelper() (helper tools.EtcdHelper, err error) { |
|
277 |
- // Connect and setup etcd interfaces |
|
278 |
- client, err := cfg.getAndTestEtcdClient() |
|
279 |
- if err != nil { |
|
280 |
- return tools.EtcdHelper{}, err |
|
281 |
- } |
|
282 |
- |
|
283 |
- version := cfg.StorageVersion |
|
284 |
- if len(version) == 0 { |
|
285 |
- version = latest.Version |
|
286 |
- } |
|
287 |
- interfaces, err := latest.InterfacesFor(version) |
|
288 |
- if err != nil { |
|
289 |
- return helper, err |
|
290 |
- } |
|
291 |
- return tools.EtcdHelper{client, interfaces.Codec, tools.RuntimeVersionAdapter{interfaces.MetadataAccessor}}, nil |
|
292 |
-} |
|
293 |
- |
|
294 |
-// defaultHostname returns the default hostname for this system. |
|
295 |
-func defaultHostname() (string, error) { |
|
296 |
- // Note: We use exec here instead of os.Hostname() because we |
|
297 |
- // want the FQDN, and this is the easiest way to get it. |
|
298 |
- fqdn, err := exec.Command("hostname", "-f").Output() |
|
299 |
- if err != nil { |
|
300 |
- return "", fmt.Errorf("Couldn't determine hostname: %v", err) |
|
301 |
- } |
|
302 |
- return strings.TrimSpace(string(fqdn)), nil |
|
303 |
-} |
304 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,528 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "testing" |
|
5 |
- |
|
6 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
7 |
- clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" |
|
8 |
- "github.com/openshift/origin/pkg/cmd/util" |
|
9 |
-) |
|
10 |
- |
|
11 |
-func TestMasterPublicAddressDefaulting(t *testing.T) { |
|
12 |
- expected := "http://example.com:9012" |
|
13 |
- |
|
14 |
- cfg := NewDefaultConfig() |
|
15 |
- cfg.MasterAddr.Set(expected) |
|
16 |
- |
|
17 |
- actual, err := cfg.GetMasterPublicAddress() |
|
18 |
- if err != nil { |
|
19 |
- t.Errorf("unexpected error: %v", err) |
|
20 |
- } |
|
21 |
- if expected != actual.String() { |
|
22 |
- t.Errorf("expected %v, got %v", expected, actual) |
|
23 |
- } |
|
24 |
-} |
|
25 |
- |
|
26 |
-func TestMasterPublicAddressExplicit(t *testing.T) { |
|
27 |
- expected := "http://external.com:12445" |
|
28 |
- |
|
29 |
- cfg := NewDefaultConfig() |
|
30 |
- cfg.MasterAddr.Set("http://internal.com:9012") |
|
31 |
- cfg.MasterPublicAddr.Set(expected) |
|
32 |
- |
|
33 |
- actual, err := cfg.GetMasterPublicAddress() |
|
34 |
- if err != nil { |
|
35 |
- t.Errorf("unexpected error: %v", err) |
|
36 |
- } |
|
37 |
- if expected != actual.String() { |
|
38 |
- t.Errorf("expected %v, got %v", expected, actual) |
|
39 |
- } |
|
40 |
-} |
|
41 |
- |
|
42 |
-func TestAssetPublicAddressDefaulting(t *testing.T) { |
|
43 |
- master := "http://example.com:9011" |
|
44 |
- expected := "http://example.com:9012" |
|
45 |
- |
|
46 |
- cfg := NewDefaultConfig() |
|
47 |
- cfg.MasterAddr.Set(master) |
|
48 |
- |
|
49 |
- actual, err := cfg.GetAssetPublicAddress() |
|
50 |
- if err != nil { |
|
51 |
- t.Errorf("unexpected error: %v", err) |
|
52 |
- } |
|
53 |
- if expected != actual.String() { |
|
54 |
- t.Errorf("expected %v, got %v", expected, actual) |
|
55 |
- } |
|
56 |
-} |
|
57 |
- |
|
58 |
-func TestAssetPublicAddressExplicit(t *testing.T) { |
|
59 |
- master := "http://example.com:9011" |
|
60 |
- expected := "https://example.com:9014" |
|
61 |
- |
|
62 |
- cfg := NewDefaultConfig() |
|
63 |
- cfg.MasterAddr.Set(master) |
|
64 |
- cfg.AssetPublicAddr.Set(expected) |
|
65 |
- |
|
66 |
- actual, err := cfg.GetAssetPublicAddress() |
|
67 |
- if err != nil { |
|
68 |
- t.Errorf("unexpected error: %v", err) |
|
69 |
- } |
|
70 |
- if expected != actual.String() { |
|
71 |
- t.Errorf("expected %v, got %v", expected, actual) |
|
72 |
- } |
|
73 |
-} |
|
74 |
- |
|
75 |
-func TestAssetBindAddressDefaulting(t *testing.T) { |
|
76 |
- bind := "1.2.3.4:9011" |
|
77 |
- expected := "1.2.3.4:9012" |
|
78 |
- |
|
79 |
- cfg := NewDefaultConfig() |
|
80 |
- cfg.BindAddr.Set(bind) |
|
81 |
- |
|
82 |
- actual := cfg.GetAssetBindAddress() |
|
83 |
- if expected != actual { |
|
84 |
- t.Errorf("expected %v, got %v", expected, actual) |
|
85 |
- } |
|
86 |
-} |
|
87 |
- |
|
88 |
-func TestAssetBindAddressExplicit(t *testing.T) { |
|
89 |
- bind := "1.2.3.4:9011" |
|
90 |
- expected := "2.3.4.5:1234" |
|
91 |
- |
|
92 |
- cfg := NewDefaultConfig() |
|
93 |
- cfg.BindAddr.Set(bind) |
|
94 |
- cfg.AssetBindAddr.Set(expected) |
|
95 |
- |
|
96 |
- actual := cfg.GetAssetBindAddress() |
|
97 |
- if expected != actual { |
|
98 |
- t.Errorf("expected %v, got %v", expected, actual) |
|
99 |
- } |
|
100 |
-} |
|
101 |
- |
|
102 |
-func TestKubernetesPublicAddressDefaultToKubernetesAddress(t *testing.T) { |
|
103 |
- expected := "http://example.com:9012" |
|
104 |
- |
|
105 |
- cfg := NewDefaultConfig() |
|
106 |
- cfg.KubernetesAddr.Set(expected) |
|
107 |
- cfg.MasterPublicAddr.Set("unexpectedpublicmaster") |
|
108 |
- cfg.MasterAddr.Set("unexpectedmaster") |
|
109 |
- |
|
110 |
- actual, err := cfg.GetKubernetesPublicAddress() |
|
111 |
- if err != nil { |
|
112 |
- t.Fatalf("unexpected error: %v", err) |
|
113 |
- } |
|
114 |
- if expected != actual.String() { |
|
115 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
116 |
- } |
|
117 |
-} |
|
118 |
- |
|
119 |
-func TestKubernetesPublicAddressDefaultToPublicMasterAddress(t *testing.T) { |
|
120 |
- expected := "http://example.com:9012" |
|
121 |
- |
|
122 |
- cfg := NewDefaultConfig() |
|
123 |
- cfg.MasterPublicAddr.Set(expected) |
|
124 |
- cfg.MasterAddr.Set("unexpectedmaster") |
|
125 |
- |
|
126 |
- actual, err := cfg.GetKubernetesPublicAddress() |
|
127 |
- if err != nil { |
|
128 |
- t.Fatalf("unexpected error: %v", err) |
|
129 |
- } |
|
130 |
- if expected != actual.String() { |
|
131 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
132 |
- } |
|
133 |
-} |
|
134 |
- |
|
135 |
-func TestKubernetesPublicAddressDefaultToMasterAddress(t *testing.T) { |
|
136 |
- expected := "http://example.com:9012" |
|
137 |
- |
|
138 |
- cfg := NewDefaultConfig() |
|
139 |
- cfg.MasterAddr.Set(expected) |
|
140 |
- |
|
141 |
- actual, err := cfg.GetKubernetesPublicAddress() |
|
142 |
- if err != nil { |
|
143 |
- t.Fatalf("unexpected error: %v", err) |
|
144 |
- } |
|
145 |
- if expected != actual.String() { |
|
146 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
147 |
- } |
|
148 |
-} |
|
149 |
- |
|
150 |
-func TestKubernetesPublicAddressExplicit(t *testing.T) { |
|
151 |
- expected := "http://external.com:12445" |
|
152 |
- |
|
153 |
- cfg := NewDefaultConfig() |
|
154 |
- cfg.MasterAddr.Set("http://internal.com:9012") |
|
155 |
- cfg.KubernetesAddr.Set("http://internal.com:9013") |
|
156 |
- cfg.MasterPublicAddr.Set("http://internal.com:9014") |
|
157 |
- cfg.KubernetesPublicAddr.Set(expected) |
|
158 |
- |
|
159 |
- actual, err := cfg.GetKubernetesPublicAddress() |
|
160 |
- if err != nil { |
|
161 |
- t.Fatalf("unexpected error: %v", err) |
|
162 |
- } |
|
163 |
- if expected != actual.String() { |
|
164 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
165 |
- } |
|
166 |
-} |
|
167 |
- |
|
168 |
-func TestKubernetesAddressDefaulting(t *testing.T) { |
|
169 |
- expected := "http://example.com:9012" |
|
170 |
- |
|
171 |
- cfg := NewDefaultConfig() |
|
172 |
- cfg.MasterAddr.Set(expected) |
|
173 |
- |
|
174 |
- actual, err := cfg.GetKubernetesAddress() |
|
175 |
- if err != nil { |
|
176 |
- t.Fatalf("unexpected error: %v", err) |
|
177 |
- } |
|
178 |
- if expected != actual.String() { |
|
179 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
180 |
- } |
|
181 |
-} |
|
182 |
- |
|
183 |
-func TestKubernetesAddressExplicit(t *testing.T) { |
|
184 |
- expected := "http://external.com:12445" |
|
185 |
- |
|
186 |
- cfg := NewDefaultConfig() |
|
187 |
- cfg.MasterAddr.Set("http://internal.com:9012") |
|
188 |
- cfg.KubernetesAddr.Set(expected) |
|
189 |
- |
|
190 |
- actual, err := cfg.GetKubernetesAddress() |
|
191 |
- if err != nil { |
|
192 |
- t.Fatalf("unexpected error: %v", err) |
|
193 |
- } |
|
194 |
- if expected != actual.String() { |
|
195 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
196 |
- } |
|
197 |
-} |
|
198 |
- |
|
199 |
-func TestEtcdAddressDefaulting(t *testing.T) { |
|
200 |
- expected := "http://example.com:4001" |
|
201 |
- master := "https://example.com:9012" |
|
202 |
- |
|
203 |
- cfg := NewDefaultConfig() |
|
204 |
- cfg.MasterAddr.Set(master) |
|
205 |
- |
|
206 |
- actual, err := cfg.GetEtcdAddress() |
|
207 |
- if err != nil { |
|
208 |
- t.Fatalf("unexpected error: %v", err) |
|
209 |
- } |
|
210 |
- if expected != actual.String() { |
|
211 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
212 |
- } |
|
213 |
-} |
|
214 |
- |
|
215 |
-func TestEtcdAddressExplicit(t *testing.T) { |
|
216 |
- expected := "http://external.com:12445" |
|
217 |
- |
|
218 |
- cfg := NewDefaultConfig() |
|
219 |
- cfg.MasterAddr.Set("http://internal.com:9012") |
|
220 |
- cfg.EtcdAddr.Set(expected) |
|
221 |
- |
|
222 |
- actual, err := cfg.GetEtcdAddress() |
|
223 |
- if err != nil { |
|
224 |
- t.Fatalf("unexpected error: %v", err) |
|
225 |
- } |
|
226 |
- if expected != actual.String() { |
|
227 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
228 |
- } |
|
229 |
-} |
|
230 |
- |
|
231 |
-func TestEtcdBindAddressDefault(t *testing.T) { |
|
232 |
- expected := "0.0.0.0:4001" |
|
233 |
- |
|
234 |
- cfg := NewDefaultConfig() |
|
235 |
- actual := cfg.GetEtcdBindAddress() |
|
236 |
- if expected != actual { |
|
237 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
238 |
- } |
|
239 |
-} |
|
240 |
- |
|
241 |
-func TestEtcdPeerAddressDefault(t *testing.T) { |
|
242 |
- expected := "0.0.0.0:7001" |
|
243 |
- |
|
244 |
- cfg := NewDefaultConfig() |
|
245 |
- actual := cfg.GetEtcdPeerBindAddress() |
|
246 |
- if expected != actual { |
|
247 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
248 |
- } |
|
249 |
-} |
|
250 |
- |
|
251 |
-func TestEtcdBindAddressDefaultToBind(t *testing.T) { |
|
252 |
- expected := "1.2.3.4:4001" |
|
253 |
- |
|
254 |
- cfg := NewDefaultConfig() |
|
255 |
- cfg.BindAddr.Set("https://1.2.3.4:8080") |
|
256 |
- |
|
257 |
- actual := cfg.GetEtcdBindAddress() |
|
258 |
- if expected != actual { |
|
259 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
260 |
- } |
|
261 |
-} |
|
262 |
- |
|
263 |
-func TestMasterAddressDefaultingToBindValues(t *testing.T) { |
|
264 |
- defaultIP, err := util.DefaultLocalIP4() |
|
265 |
- if err != nil { |
|
266 |
- t.Fatalf("unexpected error: %v", err) |
|
267 |
- } |
|
268 |
- expected := "http://" + defaultIP.String() + ":9012" |
|
269 |
- |
|
270 |
- cfg := NewDefaultConfig() |
|
271 |
- cfg.StartMaster = true |
|
272 |
- cfg.BindAddr.Set("http://0.0.0.0:9012") |
|
273 |
- |
|
274 |
- actual, err := cfg.GetMasterAddress() |
|
275 |
- if err != nil { |
|
276 |
- t.Fatalf("unexpected error: %v", err) |
|
277 |
- } |
|
278 |
- if expected != actual.String() { |
|
279 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
280 |
- } |
|
281 |
-} |
|
282 |
- |
|
283 |
-func TestMasterAddressExplicit(t *testing.T) { |
|
284 |
- expected := "http://external.com:12445" |
|
285 |
- |
|
286 |
- cfg := NewDefaultConfig() |
|
287 |
- cfg.MasterAddr.Set(expected) |
|
288 |
- |
|
289 |
- actual, err := cfg.GetMasterAddress() |
|
290 |
- if err != nil { |
|
291 |
- t.Fatalf("unexpected error: %v", err) |
|
292 |
- } |
|
293 |
- if expected != actual.String() { |
|
294 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
295 |
- } |
|
296 |
-} |
|
297 |
- |
|
298 |
-func TestKubeClientForExternalKubernetesMasterWithNoConfig(t *testing.T) { |
|
299 |
- expected := "https://localhost:8443" |
|
300 |
- |
|
301 |
- cfg := NewDefaultConfig() |
|
302 |
- cfg.StartMaster = true |
|
303 |
- cfg.MasterAddr.Set(expected) |
|
304 |
- |
|
305 |
- actual, err := cfg.GetKubernetesAddress() |
|
306 |
- if err != nil { |
|
307 |
- t.Fatalf("unexpected error: %v", err) |
|
308 |
- } |
|
309 |
- if expected != actual.String() { |
|
310 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
311 |
- } |
|
312 |
- |
|
313 |
- _, config, err := cfg.GetKubeClient() |
|
314 |
- if err != nil { |
|
315 |
- t.Fatalf("unexpected error: %v", err) |
|
316 |
- } |
|
317 |
- if expected != config.Host { |
|
318 |
- t.Fatalf("expected %v, got %v", expected, config.Host) |
|
319 |
- } |
|
320 |
-} |
|
321 |
- |
|
322 |
-func TestKubeClientForNodeWithNoConfig(t *testing.T) { |
|
323 |
- expected := "https://localhost:8443" |
|
324 |
- |
|
325 |
- cfg := NewDefaultConfig() |
|
326 |
- cfg.StartNode = true |
|
327 |
- cfg.MasterAddr.Set(expected) |
|
328 |
- |
|
329 |
- actual, err := cfg.GetKubernetesAddress() |
|
330 |
- if err != nil { |
|
331 |
- t.Fatalf("unexpected error: %v", err) |
|
332 |
- } |
|
333 |
- if expected != actual.String() { |
|
334 |
- t.Fatalf("expected %v, got %v", expected, actual) |
|
335 |
- } |
|
336 |
- |
|
337 |
- _, config, err := cfg.GetKubeClient() |
|
338 |
- if err != nil { |
|
339 |
- t.Fatalf("unexpected error: %v", err) |
|
340 |
- } |
|
341 |
- if expected != config.Host { |
|
342 |
- t.Fatalf("expected %v, got %v", expected, config.Host) |
|
343 |
- } |
|
344 |
-} |
|
345 |
- |
|
346 |
-func TestKubeClientForExternalKubernetesMasterWithConfig(t *testing.T) { |
|
347 |
- expectedServer := "https://some-other-server:1234" |
|
348 |
- expectedUser := "myuser" |
|
349 |
- |
|
350 |
- cfg := NewDefaultConfig() |
|
351 |
- cfg.StartMaster = true |
|
352 |
- cfg.ClientConfigLoadingRules, cfg.ClientConfig = makeKubeconfig(expectedServer, expectedUser) |
|
353 |
- |
|
354 |
- actualPublic, err := cfg.GetKubernetesPublicAddress() |
|
355 |
- if err != nil { |
|
356 |
- t.Fatalf("unexpected error: %v", err) |
|
357 |
- } |
|
358 |
- if expectedServer != actualPublic.String() { |
|
359 |
- t.Fatalf("expected %v, got %v", expectedServer, actualPublic) |
|
360 |
- } |
|
361 |
- |
|
362 |
- actual, err := cfg.GetKubernetesAddress() |
|
363 |
- if err != nil { |
|
364 |
- t.Fatalf("unexpected error: %v", err) |
|
365 |
- } |
|
366 |
- if expectedServer != actual.String() { |
|
367 |
- t.Fatalf("expected %v, got %v", expectedServer, actual) |
|
368 |
- } |
|
369 |
- |
|
370 |
- _, config, err := cfg.GetKubeClient() |
|
371 |
- if err != nil { |
|
372 |
- t.Fatalf("unexpected error: %v", err) |
|
373 |
- } |
|
374 |
- if config.Host != expectedServer { |
|
375 |
- t.Fatalf("expected %v, got %v", expectedServer, config.Host) |
|
376 |
- } |
|
377 |
- if config.Username != expectedUser { |
|
378 |
- t.Fatalf("expected %v, got %v", expectedUser, config.Username) |
|
379 |
- } |
|
380 |
-} |
|
381 |
- |
|
382 |
-func TestKubeClientForNodeWithConfig(t *testing.T) { |
|
383 |
- expectedServer := "https://some-other-server:1234" |
|
384 |
- expectedUser := "myuser" |
|
385 |
- |
|
386 |
- cfg := NewDefaultConfig() |
|
387 |
- cfg.StartNode = true |
|
388 |
- cfg.ClientConfigLoadingRules, cfg.ClientConfig = makeKubeconfig(expectedServer, expectedUser) |
|
389 |
- |
|
390 |
- actualPublic, err := cfg.GetKubernetesPublicAddress() |
|
391 |
- if err != nil { |
|
392 |
- t.Fatalf("unexpected error: %v", err) |
|
393 |
- } |
|
394 |
- if expectedServer != actualPublic.String() { |
|
395 |
- t.Fatalf("expected %v, got %v", expectedServer, actualPublic) |
|
396 |
- } |
|
397 |
- |
|
398 |
- actual, err := cfg.GetKubernetesAddress() |
|
399 |
- if err != nil { |
|
400 |
- t.Fatalf("unexpected error: %v", err) |
|
401 |
- } |
|
402 |
- if expectedServer != actual.String() { |
|
403 |
- t.Fatalf("expected %v, got %v", expectedServer, actual) |
|
404 |
- } |
|
405 |
- |
|
406 |
- _, config, err := cfg.GetKubeClient() |
|
407 |
- if err != nil { |
|
408 |
- t.Fatalf("unexpected error: %v", err) |
|
409 |
- } |
|
410 |
- if config.Host != expectedServer { |
|
411 |
- t.Fatalf("expected %v, got %v", expectedServer, config.Host) |
|
412 |
- } |
|
413 |
- if config.Username != expectedUser { |
|
414 |
- t.Fatalf("expected %v, got %v", expectedUser, config.Username) |
|
415 |
- } |
|
416 |
-} |
|
417 |
- |
|
418 |
-func TestKubeClientForExternalKubernetesMasterWithErrorKubeconfig(t *testing.T) { |
|
419 |
- cfg := NewDefaultConfig() |
|
420 |
- cfg.StartMaster = true |
|
421 |
- cfg.ClientConfigLoadingRules, cfg.ClientConfig = makeErrorKubeconfig() |
|
422 |
- |
|
423 |
- // GetKubernetesPublicAddress hits the invalid kubeconfig in the fallback chain |
|
424 |
- _, err := cfg.GetKubernetesPublicAddress() |
|
425 |
- if err == nil { |
|
426 |
- t.Fatalf("expected error, got none") |
|
427 |
- } |
|
428 |
- |
|
429 |
- // GetKubernetesAddress hits the invalid kubeconfig in the fallback chain |
|
430 |
- _, err = cfg.GetKubernetesAddress() |
|
431 |
- if err == nil { |
|
432 |
- t.Fatalf("expected error, got none") |
|
433 |
- } |
|
434 |
- |
|
435 |
- // Should not get a client |
|
436 |
- if _, _, err = cfg.GetKubeClient(); err == nil { |
|
437 |
- t.Fatalf("expected error, got none") |
|
438 |
- } |
|
439 |
-} |
|
440 |
- |
|
441 |
-func TestKubeClientForExternalKubernetesMasterWithConflictingKubernetesAddress(t *testing.T) { |
|
442 |
- expectedServer := "https://some-other-server:1234" |
|
443 |
- expectedUser := "myuser" |
|
444 |
- |
|
445 |
- cfg := NewDefaultConfig() |
|
446 |
- cfg.StartMaster = true |
|
447 |
- // Explicitly set --kubernetes must match --kubeconfig or return an error |
|
448 |
- cfg.KubernetesAddr.Set(expectedServer) |
|
449 |
- cfg.ClientConfigLoadingRules, cfg.ClientConfig = makeKubeconfig("https://another-server:2345", expectedUser) |
|
450 |
- |
|
451 |
- // GetKubernetesAddress returns the explicitly set address |
|
452 |
- actual, err := cfg.GetKubernetesAddress() |
|
453 |
- if err != nil { |
|
454 |
- t.Fatalf("unexpected error: %v", err) |
|
455 |
- } |
|
456 |
- if expectedServer != actual.String() { |
|
457 |
- t.Fatalf("expected %v, got %v", expectedServer, actual) |
|
458 |
- } |
|
459 |
- |
|
460 |
- // Should not get a client that might let us send credentials to the wrong server |
|
461 |
- if _, _, err := cfg.GetKubeClient(); err == nil { |
|
462 |
- t.Fatalf("expected error, got none") |
|
463 |
- } |
|
464 |
-} |
|
465 |
- |
|
466 |
-func TestKubeClientForNodeWithConflictingKubernetesAddress(t *testing.T) { |
|
467 |
- expectedServer := "https://some-other-server:1234" |
|
468 |
- expectedUser := "myuser" |
|
469 |
- |
|
470 |
- cfg := NewDefaultConfig() |
|
471 |
- cfg.StartNode = true |
|
472 |
- cfg.KubernetesAddr.Set(expectedServer) |
|
473 |
- cfg.ClientConfigLoadingRules, cfg.ClientConfig = makeKubeconfig("https://another-server:2345", expectedUser) |
|
474 |
- |
|
475 |
- // GetKubernetesAddress returns the explicitly set address |
|
476 |
- actualServer, err := cfg.GetKubernetesAddress() |
|
477 |
- if err != nil { |
|
478 |
- t.Fatalf("unexpected error: %v", err) |
|
479 |
- } |
|
480 |
- if expectedServer != actualServer.String() { |
|
481 |
- t.Fatalf("expected %v, got %v", expectedServer, actualServer) |
|
482 |
- } |
|
483 |
- |
|
484 |
- // Should not get a client that might let us send credentials to the wrong server |
|
485 |
- if _, _, err := cfg.GetKubeClient(); err == nil { |
|
486 |
- t.Fatalf("expected error, got none") |
|
487 |
- } |
|
488 |
-} |
|
489 |
- |
|
490 |
-func makeEmptyKubeconfig() (clientcmd.ClientConfigLoadingRules, clientcmd.ClientConfig) { |
|
491 |
- // Set a non-empty CommandLinePath to trigger loading |
|
492 |
- loadingRules := clientcmd.ClientConfigLoadingRules{CommandLinePath: "specified"} |
|
493 |
- |
|
494 |
- clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( |
|
495 |
- // Set empty loading rules to avoid missing file errors |
|
496 |
- &clientcmd.ClientConfigLoadingRules{}, |
|
497 |
- &clientcmd.ConfigOverrides{}, |
|
498 |
- ) |
|
499 |
- return loadingRules, clientConfig |
|
500 |
-} |
|
501 |
- |
|
502 |
-func makeErrorKubeconfig() (clientcmd.ClientConfigLoadingRules, clientcmd.ClientConfig) { |
|
503 |
- // Set a non-empty CommandLinePath to trigger loading |
|
504 |
- loadingRules := clientcmd.ClientConfigLoadingRules{CommandLinePath: "missing-file"} |
|
505 |
- |
|
506 |
- clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( |
|
507 |
- &loadingRules, |
|
508 |
- &clientcmd.ConfigOverrides{}, |
|
509 |
- ) |
|
510 |
- return loadingRules, clientConfig |
|
511 |
-} |
|
512 |
- |
|
513 |
-func makeKubeconfig(server, user string) (clientcmd.ClientConfigLoadingRules, clientcmd.ClientConfig) { |
|
514 |
- // Set a non-empty CommandLinePath to trigger loading |
|
515 |
- loadingRules := clientcmd.ClientConfigLoadingRules{CommandLinePath: "specified"} |
|
516 |
- |
|
517 |
- clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( |
|
518 |
- // Set empty loading rules to avoid missing file errors |
|
519 |
- &clientcmd.ClientConfigLoadingRules{}, |
|
520 |
- // Override the server and user in client config to simulate loading from a file |
|
521 |
- &clientcmd.ConfigOverrides{ |
|
522 |
- ClusterInfo: clientcmdapi.Cluster{Server: server}, |
|
523 |
- AuthInfo: clientcmdapi.AuthInfo{Username: user}, |
|
524 |
- }, |
|
525 |
- ) |
|
526 |
- |
|
527 |
- return loadingRules, clientConfig |
|
528 |
-} |
... | ... |
@@ -20,92 +20,102 @@ import ( |
20 | 20 |
"strconv" |
21 | 21 |
"time" |
22 | 22 |
|
23 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
|
24 |
- kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
25 |
- clientcmd "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
26 |
- clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" |
|
27 | 23 |
"github.com/golang/glog" |
24 |
+ |
|
25 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
|
26 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
27 |
+ |
|
28 | 28 |
"github.com/openshift/origin/pkg/auth/authenticator/request/x509request" |
29 | 29 |
) |
30 | 30 |
|
31 |
-func filenamesFromDir(dir string) (string, string, string) { |
|
32 |
- return filepath.Join(dir, "root.crt"), filepath.Join(dir, "cert.crt"), filepath.Join(dir, "key.key") |
|
33 |
-} |
|
34 |
- |
|
35 | 31 |
type TLSCertificateConfig struct { |
36 |
- CAFile string |
|
37 |
- CertFile string |
|
38 |
- KeyFile string |
|
39 |
- |
|
40 |
- Roots []*x509.Certificate |
|
41 | 32 |
Certs []*x509.Certificate |
42 | 33 |
Key crypto.PrivateKey |
43 | 34 |
} |
44 | 35 |
|
45 |
-func (c *TLSCertificateConfig) writeDir(dir string) error { |
|
46 |
- c.CAFile, c.CertFile, c.KeyFile = filenamesFromDir(dir) |
|
47 |
- |
|
48 |
- // mkdir |
|
49 |
- if err := os.MkdirAll(dir, os.FileMode(0755)); err != nil { |
|
50 |
- return err |
|
51 |
- } |
|
36 |
+type TLSCARoots struct { |
|
37 |
+ Roots []*x509.Certificate |
|
38 |
+} |
|
52 | 39 |
|
53 |
- // write certs and keys |
|
54 |
- if err := writeCertificates(c.CAFile, c.Roots...); err != nil { |
|
40 |
+func (c *TLSCertificateConfig) writeCertConfig(certFile, keyFile string) error { |
|
41 |
+ if err := writeCertificates(certFile, c.Certs...); err != nil { |
|
55 | 42 |
return err |
56 | 43 |
} |
57 |
- if err := writeCertificates(c.CertFile, c.Certs...); err != nil { |
|
44 |
+ if err := writeKeyFile(keyFile, c.Key); err != nil { |
|
58 | 45 |
return err |
59 | 46 |
} |
60 |
- if err := writeKeyFile(c.KeyFile, c.Key); err != nil { |
|
47 |
+ return nil |
|
48 |
+} |
|
49 |
+func (c *TLSCARoots) writeCARoots(rootFile string) error { |
|
50 |
+ if err := writeCertificates(rootFile, c.Roots...); err != nil { |
|
61 | 51 |
return err |
62 | 52 |
} |
63 | 53 |
return nil |
64 | 54 |
} |
65 | 55 |
|
66 |
-func newTLSCertificateConfig(dir string) (*TLSCertificateConfig, error) { |
|
67 |
- caFile, certFile, keyFile := filenamesFromDir(dir) |
|
68 |
- config := &TLSCertificateConfig{ |
|
69 |
- CAFile: caFile, |
|
70 |
- CertFile: certFile, |
|
71 |
- KeyFile: keyFile, |
|
56 |
+func GetTLSCARoots(caFile string) (*TLSCARoots, error) { |
|
57 |
+ if len(caFile) == 0 { |
|
58 |
+ return nil, errors.New("caFile missing") |
|
72 | 59 |
} |
73 | 60 |
|
74 |
- if caFile != "" { |
|
75 |
- caPEMBlock, err := ioutil.ReadFile(caFile) |
|
76 |
- if err != nil { |
|
77 |
- return nil, err |
|
78 |
- } |
|
79 |
- config.Roots, err = certsFromPEM(caPEMBlock) |
|
80 |
- if err != nil { |
|
81 |
- return nil, fmt.Errorf("Error reading %s: %s", caFile, err) |
|
82 |
- } |
|
61 |
+ caPEMBlock, err := ioutil.ReadFile(caFile) |
|
62 |
+ if err != nil { |
|
63 |
+ return nil, err |
|
64 |
+ } |
|
65 |
+ roots, err := certsFromPEM(caPEMBlock) |
|
66 |
+ if err != nil { |
|
67 |
+ return nil, fmt.Errorf("Error reading %s: %s", caFile, err) |
|
83 | 68 |
} |
84 | 69 |
|
85 |
- if certFile != "" { |
|
86 |
- certPEMBlock, err := ioutil.ReadFile(certFile) |
|
87 |
- if err != nil { |
|
88 |
- return nil, err |
|
89 |
- } |
|
90 |
- config.Certs, err = certsFromPEM(certPEMBlock) |
|
91 |
- if err != nil { |
|
92 |
- return nil, fmt.Errorf("Error reading %s: %s", caFile, err) |
|
93 |
- } |
|
70 |
+ return &TLSCARoots{roots}, nil |
|
71 |
+} |
|
94 | 72 |
|
95 |
- if keyFile != "" { |
|
96 |
- keyPEMBlock, err := ioutil.ReadFile(keyFile) |
|
97 |
- if err != nil { |
|
98 |
- return nil, err |
|
99 |
- } |
|
100 |
- keyPairCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) |
|
101 |
- if err != nil { |
|
102 |
- return nil, err |
|
103 |
- } |
|
104 |
- config.Key = keyPairCert.PrivateKey |
|
105 |
- } |
|
73 |
+func GetTLSCertificateConfig(certFile, keyFile string) (*TLSCertificateConfig, error) { |
|
74 |
+ if len(certFile) == 0 { |
|
75 |
+ return nil, errors.New("certFile missing") |
|
76 |
+ } |
|
77 |
+ if len(keyFile) == 0 { |
|
78 |
+ return nil, errors.New("keyFile missing") |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ certPEMBlock, err := ioutil.ReadFile(certFile) |
|
82 |
+ if err != nil { |
|
83 |
+ return nil, err |
|
84 |
+ } |
|
85 |
+ certs, err := certsFromPEM(certPEMBlock) |
|
86 |
+ if err != nil { |
|
87 |
+ return nil, fmt.Errorf("Error reading %s: %s", certFile, err) |
|
88 |
+ } |
|
89 |
+ |
|
90 |
+ keyPEMBlock, err := ioutil.ReadFile(keyFile) |
|
91 |
+ if err != nil { |
|
92 |
+ return nil, err |
|
93 |
+ } |
|
94 |
+ keyPairCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) |
|
95 |
+ if err != nil { |
|
96 |
+ return nil, err |
|
97 |
+ } |
|
98 |
+ key := keyPairCert.PrivateKey |
|
99 |
+ |
|
100 |
+ return &TLSCertificateConfig{certs, key}, nil |
|
101 |
+} |
|
102 |
+ |
|
103 |
+func CertPoolFromFile(filename string) (*x509.CertPool, error) { |
|
104 |
+ pemBlock, err := ioutil.ReadFile(filename) |
|
105 |
+ if err != nil { |
|
106 |
+ return nil, err |
|
107 |
+ } |
|
108 |
+ certs, err := certsFromPEM(pemBlock) |
|
109 |
+ if err != nil { |
|
110 |
+ return nil, fmt.Errorf("Error reading %s: %s", filename, err) |
|
106 | 111 |
} |
107 | 112 |
|
108 |
- return config, nil |
|
113 |
+ roots := x509.NewCertPool() |
|
114 |
+ for _, root := range certs { |
|
115 |
+ roots.AddCert(root) |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ return roots, nil |
|
109 | 119 |
} |
110 | 120 |
|
111 | 121 |
func certsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) { |
... | ... |
@@ -145,55 +155,31 @@ var ( |
145 | 145 |
) |
146 | 146 |
|
147 | 147 |
type CA struct { |
148 |
- Dir string |
|
149 | 148 |
SerialFile string |
150 | 149 |
Serial int64 |
151 | 150 |
Config *TLSCertificateConfig |
152 | 151 |
} |
153 | 152 |
|
154 |
-// InitCA ensures a certificate authority structure exists in the given directory, creating it if necessary: |
|
155 |
-// <dir>/ |
|
156 |
-// ca/ |
|
157 |
-// root.crt - Root certificate bundle. |
|
158 |
-// cert.crt - Signing certificate |
|
159 |
-// key.key - Private key |
|
160 |
-// serial.txt - Stores the highest serial number generated by this CA |
|
161 |
-func InitCA(dir string, name string) (*CA, error) { |
|
162 |
- caDir := filepath.Join(dir, "ca") |
|
153 |
+func EnsureCA(certFile, keyFile, serialFile, name string) (*CA, error) { |
|
154 |
+ if ca, err := GetCA(certFile, keyFile, serialFile); err == nil { |
|
155 |
+ return ca, nil |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ return MakeCA(certFile, keyFile, serialFile, name) |
|
159 |
+} |
|
163 | 160 |
|
164 |
- caConfig, err := newTLSCertificateConfig(caDir) |
|
161 |
+func GetCA(certFile, keyFile, serialFile string) (*CA, error) { |
|
162 |
+ caConfig, err := GetTLSCertificateConfig(certFile, keyFile) |
|
165 | 163 |
if err != nil { |
166 |
- glog.V(2).Infof("Generating new CA in %s", caDir) |
|
167 |
- // Create CA cert |
|
168 |
- rootcaPublicKey, rootcaPrivateKey, err := NewKeyPair() |
|
169 |
- if err != nil { |
|
170 |
- return nil, err |
|
171 |
- } |
|
172 |
- rootcaTemplate, err := newSigningCertificateTemplate(pkix.Name{CommonName: name}) |
|
173 |
- if err != nil { |
|
174 |
- return nil, err |
|
175 |
- } |
|
176 |
- rootcaCert, err := signCertificate(rootcaTemplate, rootcaPublicKey, rootcaTemplate, rootcaPrivateKey) |
|
177 |
- if err != nil { |
|
178 |
- return nil, err |
|
179 |
- } |
|
180 |
- caConfig = &TLSCertificateConfig{ |
|
181 |
- Roots: []*x509.Certificate{rootcaCert}, |
|
182 |
- Certs: []*x509.Certificate{rootcaCert}, |
|
183 |
- Key: rootcaPrivateKey, |
|
184 |
- } |
|
185 |
- if err := caConfig.writeDir(caDir); err != nil { |
|
186 |
- return nil, err |
|
187 |
- } |
|
188 |
- } else { |
|
189 |
- glog.V(2).Infof("Using existing CA certificate in %s", caDir) |
|
164 |
+ return nil, err |
|
190 | 165 |
} |
191 | 166 |
|
192 | 167 |
// read serial file |
193 | 168 |
var serial int64 |
194 |
- serialFile := filepath.Join(caDir, "serial.txt") |
|
195 | 169 |
if serialData, err := ioutil.ReadFile(serialFile); err == nil { |
196 | 170 |
serial, _ = strconv.ParseInt(string(serialData), 10, 64) |
171 |
+ } else { |
|
172 |
+ return nil, err |
|
197 | 173 |
} |
198 | 174 |
if serial < 1 { |
199 | 175 |
serial = 1 |
... | ... |
@@ -202,159 +188,127 @@ func InitCA(dir string, name string) (*CA, error) { |
202 | 202 |
return &CA{ |
203 | 203 |
Serial: serial, |
204 | 204 |
SerialFile: serialFile, |
205 |
- Dir: dir, |
|
206 | 205 |
Config: caConfig, |
207 | 206 |
}, nil |
208 | 207 |
} |
209 | 208 |
|
210 |
-// MakeServerCert creates a folder containing certificates for the given server: |
|
211 |
-// <CA.dir>/ |
|
212 |
-// <name>/ |
|
213 |
-// root.crt - Root certificate bundle. |
|
214 |
-// cert.crt - Server certificate |
|
215 |
-// key.key - Private key |
|
216 |
-// The generated certificate has the following attributes: |
|
217 |
-// CommonName: hostnames[0] |
|
218 |
-// DNSNames subjectAltNames containing all specified hostnames |
|
219 |
-// IPAddresses subjectAltNames containing all specified hostnames which are IP addresses |
|
220 |
-// ExtKeyUsage: ExtKeyUsageServerAuth |
|
221 |
-func (ca *CA) MakeServerCert(name string, hostnames []string) (*TLSCertificateConfig, error) { |
|
222 |
- serverDir := filepath.Join(ca.Dir, name) |
|
223 |
- |
|
224 |
- server, err := newTLSCertificateConfig(serverDir) |
|
225 |
- if err == nil { |
|
226 |
- cert := server.Certs[0] |
|
227 |
- ips, dns := IPAddressesDNSNames(hostnames) |
|
228 |
- missingIps := ipsNotInSlice(ips, cert.IPAddresses) |
|
229 |
- missingDns := stringsNotInSlice(dns, cert.DNSNames) |
|
230 |
- if len(missingIps) == 0 && len(missingDns) == 0 { |
|
231 |
- glog.V(2).Infof("Using existing server certificate in %s", serverDir) |
|
232 |
- return server, nil |
|
233 |
- } |
|
209 |
+func MakeCA(certFile, keyFile, serialFile, name string) (*CA, error) { |
|
210 |
+ glog.V(2).Infof("Generating new CA for %s cert, and key in %s, %s", name, certFile, keyFile) |
|
211 |
+ // Create CA cert |
|
212 |
+ rootcaPublicKey, rootcaPrivateKey, err := NewKeyPair() |
|
213 |
+ if err != nil { |
|
214 |
+ return nil, err |
|
215 |
+ } |
|
216 |
+ rootcaTemplate, err := newSigningCertificateTemplate(pkix.Name{CommonName: name}) |
|
217 |
+ if err != nil { |
|
218 |
+ return nil, err |
|
219 |
+ } |
|
220 |
+ rootcaCert, err := signCertificate(rootcaTemplate, rootcaPublicKey, rootcaTemplate, rootcaPrivateKey) |
|
221 |
+ if err != nil { |
|
222 |
+ return nil, err |
|
223 |
+ } |
|
224 |
+ caConfig := &TLSCertificateConfig{ |
|
225 |
+ Certs: []*x509.Certificate{rootcaCert}, |
|
226 |
+ Key: rootcaPrivateKey, |
|
227 |
+ } |
|
228 |
+ if err := caConfig.writeCertConfig(certFile, keyFile); err != nil { |
|
229 |
+ return nil, err |
|
230 |
+ } |
|
231 |
+ |
|
232 |
+ if err := ioutil.WriteFile(serialFile, []byte("0"), 0644); err != nil { |
|
233 |
+ return nil, err |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ return &CA{ |
|
237 |
+ Serial: 0, |
|
238 |
+ SerialFile: serialFile, |
|
239 |
+ Config: caConfig, |
|
240 |
+ }, nil |
|
241 |
+} |
|
234 | 242 |
|
235 |
- glog.V(2).Infof("Existing server certificate in %s was missing some hostnames (%v) or IP addresses (%v)", serverDir, missingDns, missingIps) |
|
243 |
+func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames util.StringSet) (*TLSCertificateConfig, error) { |
|
244 |
+ certConfig, err := GetServerCert(certFile, keyFile, hostnames) |
|
245 |
+ if err != nil { |
|
246 |
+ return ca.MakeServerCert(certFile, keyFile, hostnames) |
|
236 | 247 |
} |
237 | 248 |
|
238 |
- glog.V(2).Infof("Generating server certificate in %s", serverDir) |
|
249 |
+ return certConfig, nil |
|
250 |
+} |
|
251 |
+ |
|
252 |
+func GetServerCert(certFile, keyFile string, hostnames util.StringSet) (*TLSCertificateConfig, error) { |
|
253 |
+ server, err := GetTLSCertificateConfig(certFile, keyFile) |
|
254 |
+ if err != nil { |
|
255 |
+ return nil, err |
|
256 |
+ } |
|
257 |
+ |
|
258 |
+ cert := server.Certs[0] |
|
259 |
+ ips, dns := IPAddressesDNSNames(hostnames.List()) |
|
260 |
+ missingIps := ipsNotInSlice(ips, cert.IPAddresses) |
|
261 |
+ missingDns := stringsNotInSlice(dns, cert.DNSNames) |
|
262 |
+ if len(missingIps) == 0 && len(missingDns) == 0 { |
|
263 |
+ glog.V(2).Infof("Found existing server certificate in %s", certFile) |
|
264 |
+ return server, nil |
|
265 |
+ } |
|
266 |
+ |
|
267 |
+ return nil, fmt.Errorf("Existing server certificate in %s was missing some hostnames (%v) or IP addresses (%v).", certFile, missingDns, missingIps) |
|
268 |
+} |
|
269 |
+ |
|
270 |
+func (ca *CA) MakeServerCert(certFile, keyFile string, hostnames util.StringSet) (*TLSCertificateConfig, error) { |
|
271 |
+ glog.V(2).Infof("Generating server certificate in %s, key in %s", certFile, keyFile) |
|
272 |
+ |
|
239 | 273 |
serverPublicKey, serverPrivateKey, _ := NewKeyPair() |
240 |
- serverTemplate, _ := newServerCertificateTemplate(pkix.Name{CommonName: hostnames[0]}, hostnames) |
|
274 |
+ serverTemplate, _ := newServerCertificateTemplate(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List()) |
|
241 | 275 |
serverCrt, _ := ca.signCertificate(serverTemplate, serverPublicKey) |
242 |
- server = &TLSCertificateConfig{ |
|
243 |
- Roots: ca.Config.Roots, |
|
276 |
+ server := &TLSCertificateConfig{ |
|
244 | 277 |
Certs: append([]*x509.Certificate{serverCrt}, ca.Config.Certs...), |
245 | 278 |
Key: serverPrivateKey, |
246 | 279 |
} |
247 |
- if err := server.writeDir(serverDir); err != nil { |
|
280 |
+ if err := server.writeCertConfig(certFile, keyFile); err != nil { |
|
248 | 281 |
return server, err |
249 | 282 |
} |
250 | 283 |
return server, nil |
251 | 284 |
} |
252 | 285 |
|
253 |
-// MakeClientConfig creates a folder containing certificates for the given client: |
|
254 |
-// <CA.dir>/ |
|
255 |
-// <clientId>/ |
|
256 |
-// root.crt - Root certificate bundle. |
|
257 |
-// cert.crt - Client certificate |
|
258 |
-// key.key - Private key |
|
259 |
-// .kubeconfig - baseKubeconfig with root.crt added to all clusters, and client user added to all contexts |
|
260 |
-// The generated certificate has the following attributes: |
|
261 |
-// Subject: |
|
262 |
-// SerialNumber: user.GetUID() |
|
263 |
-// CommonName: user.GetName() |
|
264 |
-// Organization: user.GetGroups() |
|
265 |
-// ExtKeyUsage: ExtKeyUsageClientAuth |
|
266 |
-func (ca *CA) MakeClientConfig(clientId string, u user.Info, baseKubeconfig clientcmdapi.Config) (kclient.Config, error) { |
|
267 |
- var ( |
|
268 |
- client kclient.Config |
|
269 |
- err error |
|
270 |
- caFile, certFile, keyFile string |
|
271 |
- caData, certData, keyData []byte |
|
272 |
- ) |
|
273 |
- |
|
274 |
- // Ensure the folder exists |
|
275 |
- clientDir := filepath.Join(ca.Dir, clientId) |
|
276 |
- if err := os.MkdirAll(clientDir, os.FileMode(0755)); err != nil { |
|
277 |
- return client, err |
|
278 |
- } |
|
279 |
- |
|
280 |
- caFile, certFile, keyFile = filenamesFromDir(clientDir) |
|
281 |
- if err == nil { |
|
282 |
- caData, err = ioutil.ReadFile(caFile) |
|
283 |
- } |
|
284 |
- if err == nil { |
|
285 |
- certData, err = ioutil.ReadFile(certFile) |
|
286 |
- } |
|
287 |
- if err == nil { |
|
288 |
- keyData, err = ioutil.ReadFile(keyFile) |
|
289 |
- } |
|
290 |
- |
|
291 |
- if err == nil { |
|
292 |
- glog.V(2).Infof("Using existing client certificates in %s", clientDir) |
|
293 |
- } else { |
|
294 |
- glog.V(2).Infof("Generating client certificates in %s", clientDir) |
|
295 |
- |
|
296 |
- clientPublicKey, clientPrivateKey, _ := NewKeyPair() |
|
297 |
- clientTemplate, _ := newClientCertificateTemplate(x509request.UserToSubject(u)) |
|
298 |
- clientCrt, _ := ca.signCertificate(clientTemplate, clientPublicKey) |
|
286 |
+func (ca *CA) EnsureClientCertificate(certFile, keyFile string, u user.Info) (*TLSCertificateConfig, error) { |
|
287 |
+ certConfig, err := GetTLSCertificateConfig(certFile, keyFile) |
|
288 |
+ if err != nil { |
|
289 |
+ return ca.MakeClientCertificate(certFile, keyFile, u) |
|
290 |
+ } |
|
299 | 291 |
|
300 |
- caData, err = encodeCertificates(ca.Config.Roots...) |
|
301 |
- if err != nil { |
|
302 |
- return client, err |
|
303 |
- } |
|
304 |
- certData, err = encodeCertificates(clientCrt) |
|
305 |
- if err != nil { |
|
306 |
- return client, err |
|
307 |
- } |
|
308 |
- keyData, err = encodeKey(clientPrivateKey) |
|
309 |
- if err != nil { |
|
310 |
- return client, err |
|
311 |
- } |
|
292 |
+ return certConfig, nil |
|
293 |
+} |
|
312 | 294 |
|
313 |
- // write files |
|
314 |
- if err = ioutil.WriteFile(caFile, caData, os.FileMode(0644)); err != nil { |
|
315 |
- return client, err |
|
316 |
- } |
|
317 |
- if err = ioutil.WriteFile(certFile, certData, os.FileMode(0644)); err != nil { |
|
318 |
- return client, err |
|
319 |
- } |
|
320 |
- if err = ioutil.WriteFile(keyFile, keyData, os.FileMode(0600)); err != nil { |
|
321 |
- return client, err |
|
322 |
- } |
|
295 |
+func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info) (*TLSCertificateConfig, error) { |
|
296 |
+ glog.V(2).Infof("Generating client cert in %s and key in %s", certFile, keyFile) |
|
297 |
+ // ensure parent dirs |
|
298 |
+ if err := os.MkdirAll(filepath.Dir(certFile), os.FileMode(0755)); err != nil { |
|
299 |
+ return nil, err |
|
323 | 300 |
} |
324 |
- |
|
325 |
- // Set the generated certs on a user |
|
326 |
- baseKubeconfig.AuthInfos = map[string]clientcmdapi.AuthInfo{ |
|
327 |
- clientId: { |
|
328 |
- ClientCertificateData: certData, |
|
329 |
- ClientKeyData: keyData, |
|
330 |
- }, |
|
301 |
+ if err := os.MkdirAll(filepath.Dir(keyFile), os.FileMode(0755)); err != nil { |
|
302 |
+ return nil, err |
|
331 | 303 |
} |
332 | 304 |
|
333 |
- // Set the ca certs on all clusters |
|
334 |
- for clusterName, cluster := range baseKubeconfig.Clusters { |
|
335 |
- cluster.CertificateAuthorityData = caData |
|
336 |
- baseKubeconfig.Clusters[clusterName] = cluster |
|
337 |
- } |
|
305 |
+ clientPublicKey, clientPrivateKey, _ := NewKeyPair() |
|
306 |
+ clientTemplate, _ := newClientCertificateTemplate(x509request.UserToSubject(u)) |
|
307 |
+ clientCrt, _ := ca.signCertificate(clientTemplate, clientPublicKey) |
|
338 | 308 |
|
339 |
- // Use the new user in all contexts |
|
340 |
- for contextName, context := range baseKubeconfig.Contexts { |
|
341 |
- context.AuthInfo = clientId |
|
342 |
- baseKubeconfig.Contexts[contextName] = context |
|
309 |
+ certData, err := encodeCertificates(clientCrt) |
|
310 |
+ if err != nil { |
|
311 |
+ return nil, err |
|
343 | 312 |
} |
344 |
- |
|
345 |
- if builtClient, err := clientcmd.NewDefaultClientConfig(baseKubeconfig, &clientcmd.ConfigOverrides{}).ClientConfig(); err != nil { |
|
346 |
- return client, err |
|
347 |
- } else { |
|
348 |
- client = *builtClient |
|
313 |
+ keyData, err := encodeKey(clientPrivateKey) |
|
314 |
+ if err != nil { |
|
315 |
+ return nil, err |
|
349 | 316 |
} |
350 | 317 |
|
351 |
- kubeConfigFile := filepath.Join(clientDir, ".kubeconfig") |
|
352 |
- glog.V(2).Infof("Writing client config in %s", kubeConfigFile) |
|
353 |
- if err := clientcmd.WriteToFile(baseKubeconfig, kubeConfigFile); err != nil { |
|
354 |
- return client, err |
|
318 |
+ if err = ioutil.WriteFile(certFile, certData, os.FileMode(0644)); err != nil { |
|
319 |
+ return nil, err |
|
320 |
+ } |
|
321 |
+ if err = ioutil.WriteFile(keyFile, keyData, os.FileMode(0600)); err != nil { |
|
322 |
+ return nil, err |
|
355 | 323 |
} |
356 | 324 |
|
357 |
- return client, nil |
|
325 |
+ return GetTLSCertificateConfig(certFile, keyFile) |
|
358 | 326 |
} |
359 | 327 |
|
360 | 328 |
func (ca *CA) signCertificate(template *x509.Certificate, requestKey crypto.PublicKey) (*x509.Certificate, error) { |
... | ... |
@@ -518,6 +472,11 @@ func encodeKey(key crypto.PrivateKey) ([]byte, error) { |
518 | 518 |
} |
519 | 519 |
|
520 | 520 |
func writeCertificates(path string, certs ...*x509.Certificate) error { |
521 |
+ // ensure parent dir |
|
522 |
+ if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil { |
|
523 |
+ return err |
|
524 |
+ } |
|
525 |
+ |
|
521 | 526 |
bytes, err := encodeCertificates(certs...) |
522 | 527 |
if err != nil { |
523 | 528 |
return err |
... | ... |
@@ -525,6 +484,11 @@ func writeCertificates(path string, certs ...*x509.Certificate) error { |
525 | 525 |
return ioutil.WriteFile(path, bytes, os.FileMode(0644)) |
526 | 526 |
} |
527 | 527 |
func writeKeyFile(path string, key crypto.PrivateKey) error { |
528 |
+ // ensure parent dir |
|
529 |
+ if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil { |
|
530 |
+ return err |
|
531 |
+ } |
|
532 |
+ |
|
528 | 533 |
b, err := encodeKey(key) |
529 | 534 |
if err != nil { |
530 | 535 |
return err |
... | ... |
@@ -1,12 +1,18 @@ |
1 | 1 |
package etcd |
2 | 2 |
|
3 | 3 |
import ( |
4 |
+ "fmt" |
|
4 | 5 |
"time" |
5 | 6 |
|
6 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
7 | 7 |
etcdconfig "github.com/coreos/etcd/config" |
8 | 8 |
"github.com/coreos/etcd/etcd" |
9 |
+ etcdclient "github.com/coreos/go-etcd/etcd" |
|
9 | 10 |
"github.com/golang/glog" |
11 |
+ |
|
12 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
13 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
14 |
+ |
|
15 |
+ "github.com/openshift/origin/pkg/api/latest" |
|
10 | 16 |
) |
11 | 17 |
|
12 | 18 |
// Config is an object that can run an etcd server |
... | ... |
@@ -34,3 +40,42 @@ func (c *Config) Run() { |
34 | 34 |
}, 500*time.Millisecond) |
35 | 35 |
<-server.ReadyNotify() |
36 | 36 |
} |
37 |
+ |
|
38 |
+// getAndTestEtcdClient creates an etcd client based on the provided config and waits |
|
39 |
+// until etcd server is reachable. It errors out and exits if the server cannot |
|
40 |
+// be reached for a certain amount of time. |
|
41 |
+func GetAndTestEtcdClient(etcdURL string) (*etcdclient.Client, error) { |
|
42 |
+ etcdServers := []string{etcdURL} |
|
43 |
+ etcdClient := etcdclient.NewClient(etcdServers) |
|
44 |
+ |
|
45 |
+ for i := 0; ; i++ { |
|
46 |
+ // TODO: make sure this works with etcd2 (root key may not exist) |
|
47 |
+ _, err := etcdClient.Get("/", false, false) |
|
48 |
+ if err == nil || tools.IsEtcdNotFound(err) { |
|
49 |
+ break |
|
50 |
+ } |
|
51 |
+ if i > 100 { |
|
52 |
+ return nil, fmt.Errorf("Could not reach etcd: %v", err) |
|
53 |
+ } |
|
54 |
+ time.Sleep(50 * time.Millisecond) |
|
55 |
+ } |
|
56 |
+ |
|
57 |
+ return etcdClient, nil |
|
58 |
+} |
|
59 |
+ |
|
60 |
+// newOpenShiftEtcdHelper returns an EtcdHelper for the provided arguments or an error if the version |
|
61 |
+// is incorrect. |
|
62 |
+func NewOpenShiftEtcdHelper(etcdURL string) (helper tools.EtcdHelper, err error) { |
|
63 |
+ // Connect and setup etcd interfaces |
|
64 |
+ client, err := GetAndTestEtcdClient(etcdURL) |
|
65 |
+ if err != nil { |
|
66 |
+ return tools.EtcdHelper{}, err |
|
67 |
+ } |
|
68 |
+ |
|
69 |
+ version := latest.Version |
|
70 |
+ interfaces, err := latest.InterfacesFor(version) |
|
71 |
+ if err != nil { |
|
72 |
+ return helper, err |
|
73 |
+ } |
|
74 |
+ return tools.EtcdHelper{client, interfaces.Codec, tools.RuntimeVersionAdapter{interfaces.MetadataAccessor}}, nil |
|
75 |
+} |
37 | 76 |
deleted file mode 100644 |
... | ... |
@@ -1,71 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "net" |
|
6 |
- |
|
7 |
- kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
8 |
- klatest "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" |
|
9 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" |
|
10 |
- kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
11 |
- kmaster "github.com/GoogleCloudPlatform/kubernetes/pkg/master" |
|
12 |
- |
|
13 |
- "github.com/openshift/origin/pkg/cmd/server/kubernetes" |
|
14 |
- |
|
15 |
- // Admission control plugins from upstream Kubernetes |
|
16 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" |
|
17 |
- _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit" |
|
18 |
- _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/limitranger" |
|
19 |
- _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/exists" |
|
20 |
- _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcedefaults" |
|
21 |
- _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcequota" |
|
22 |
-) |
|
23 |
- |
|
24 |
-func (cfg Config) BuildKubernetesMasterConfig(requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*kubernetes.MasterConfig, error) { |
|
25 |
- masterAddr, err := cfg.GetMasterAddress() |
|
26 |
- if err != nil { |
|
27 |
- return nil, err |
|
28 |
- } |
|
29 |
- |
|
30 |
- // Connect and setup etcd interfaces |
|
31 |
- etcdClient, err := cfg.getAndTestEtcdClient() |
|
32 |
- if err != nil { |
|
33 |
- return nil, err |
|
34 |
- } |
|
35 |
- ketcdHelper, err := kmaster.NewEtcdHelper(etcdClient, klatest.Version) |
|
36 |
- if err != nil { |
|
37 |
- return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) |
|
38 |
- } |
|
39 |
- |
|
40 |
- portalNet := net.IPNet(cfg.PortalNet) |
|
41 |
- masterIP := net.ParseIP(getHost(*masterAddr)) |
|
42 |
- if masterIP == nil { |
|
43 |
- addrs, err := net.LookupIP(getHost(*masterAddr)) |
|
44 |
- if err != nil { |
|
45 |
- return nil, fmt.Errorf("Unable to find an IP for %q - specify an IP directly? %v", getHost(*masterAddr), err) |
|
46 |
- } |
|
47 |
- if len(addrs) == 0 { |
|
48 |
- return nil, fmt.Errorf("Unable to find an IP for %q - specify an IP directly?", getHost(*masterAddr)) |
|
49 |
- } |
|
50 |
- masterIP = addrs[0] |
|
51 |
- } |
|
52 |
- |
|
53 |
- // in-order list of plug-ins that should intercept admission decisions |
|
54 |
- // TODO: add NamespaceExists |
|
55 |
- admissionControlPluginNames := []string{"LimitRanger", "ResourceQuota"} |
|
56 |
- admissionController := admission.NewFromPlugins(kubeClient, admissionControlPluginNames, "") |
|
57 |
- |
|
58 |
- kmaster := &kubernetes.MasterConfig{ |
|
59 |
- MasterIP: masterIP, |
|
60 |
- MasterPort: cfg.MasterAddr.Port, |
|
61 |
- NodeHosts: cfg.NodeList, |
|
62 |
- PortalNet: &portalNet, |
|
63 |
- RequestContextMapper: requestContextMapper, |
|
64 |
- EtcdHelper: ketcdHelper, |
|
65 |
- KubeClient: kubeClient, |
|
66 |
- Authorizer: apiserver.NewAlwaysAllowAuthorizer(), |
|
67 |
- AdmissionControl: admissionController, |
|
68 |
- } |
|
69 |
- |
|
70 |
- return kmaster, nil |
|
71 |
-} |
... | ... |
@@ -2,26 +2,23 @@ package kubernetes |
2 | 2 |
|
3 | 3 |
import ( |
4 | 4 |
"fmt" |
5 |
- "net" |
|
6 | 5 |
"time" |
7 | 6 |
|
8 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" |
|
7 |
+ "github.com/emicklei/go-restful" |
|
8 |
+ "github.com/golang/glog" |
|
9 |
+ |
|
9 | 10 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
10 | 11 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" |
11 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer" |
|
12 | 12 |
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
13 | 13 |
minionControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller" |
14 | 14 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller" |
15 | 15 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/master" |
16 | 16 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/resourcequota" |
17 | 17 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/service" |
18 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
19 | 18 |
kubeutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
20 | 19 |
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler" |
21 | 20 |
_ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithmprovider" |
22 | 21 |
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/factory" |
23 |
- "github.com/emicklei/go-restful" |
|
24 |
- "github.com/golang/glog" |
|
25 | 22 |
) |
26 | 23 |
|
27 | 24 |
const ( |
... | ... |
@@ -31,22 +28,6 @@ const ( |
31 | 31 |
KubeAPIPrefixV1Beta3 = "/api/v1beta3" |
32 | 32 |
) |
33 | 33 |
|
34 |
-// MasterConfig defines the required values to start a Kubernetes master |
|
35 |
-type MasterConfig struct { |
|
36 |
- MasterIP net.IP |
|
37 |
- MasterPort int |
|
38 |
- NodeHosts []string |
|
39 |
- PortalNet *net.IPNet |
|
40 |
- |
|
41 |
- RequestContextMapper kapi.RequestContextMapper |
|
42 |
- |
|
43 |
- EtcdHelper tools.EtcdHelper |
|
44 |
- KubeClient *kclient.Client |
|
45 |
- |
|
46 |
- Authorizer authorizer.Authorizer |
|
47 |
- AdmissionControl admission.Interface |
|
48 |
-} |
|
49 |
- |
|
50 | 34 |
// TODO: Longer term we should read this from some config store, rather than a flag. |
51 | 35 |
func (c *MasterConfig) EnsurePortalFlags() { |
52 | 36 |
if c.PortalNet == nil { |
53 | 37 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,83 @@ |
0 |
+package kubernetes |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "net" |
|
6 |
+ "strconv" |
|
7 |
+ |
|
8 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" |
|
9 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
10 |
+ klatest "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" |
|
11 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" |
|
12 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer" |
|
13 |
+ kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
14 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/master" |
|
15 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
16 |
+ |
|
17 |
+ "github.com/openshift/origin/pkg/cmd/flagtypes" |
|
18 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
19 |
+ "github.com/openshift/origin/pkg/cmd/server/etcd" |
|
20 |
+) |
|
21 |
+ |
|
22 |
+// MasterConfig defines the required values to start a Kubernetes master |
|
23 |
+type MasterConfig struct { |
|
24 |
+ MasterIP net.IP |
|
25 |
+ MasterPort int |
|
26 |
+ NodeHosts []string |
|
27 |
+ PortalNet *net.IPNet |
|
28 |
+ |
|
29 |
+ RequestContextMapper kapi.RequestContextMapper |
|
30 |
+ |
|
31 |
+ EtcdHelper tools.EtcdHelper |
|
32 |
+ KubeClient *kclient.Client |
|
33 |
+ |
|
34 |
+ Authorizer authorizer.Authorizer |
|
35 |
+ AdmissionControl admission.Interface |
|
36 |
+} |
|
37 |
+ |
|
38 |
+func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*MasterConfig, error) { |
|
39 |
+ if options.KubernetesMasterConfig == nil { |
|
40 |
+ return nil, errors.New("insufficient information to build KubernetesMasterConfig") |
|
41 |
+ } |
|
42 |
+ |
|
43 |
+ // Connect and setup etcd interfaces |
|
44 |
+ etcdClient, err := etcd.GetAndTestEtcdClient(options.EtcdClientInfo.URL) |
|
45 |
+ if err != nil { |
|
46 |
+ return nil, err |
|
47 |
+ } |
|
48 |
+ ketcdHelper, err := master.NewEtcdHelper(etcdClient, klatest.Version) |
|
49 |
+ if err != nil { |
|
50 |
+ return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) |
|
51 |
+ } |
|
52 |
+ |
|
53 |
+ portalNet := net.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet)) |
|
54 |
+ |
|
55 |
+ // in-order list of plug-ins that should intercept admission decisions |
|
56 |
+ // TODO: add NamespaceExists |
|
57 |
+ admissionControlPluginNames := []string{"LimitRanger", "ResourceQuota"} |
|
58 |
+ admissionController := admission.NewFromPlugins(kubeClient, admissionControlPluginNames, "") |
|
59 |
+ |
|
60 |
+ host, portString, err := net.SplitHostPort(options.ServingInfo.BindAddress) |
|
61 |
+ if err != nil { |
|
62 |
+ return nil, err |
|
63 |
+ } |
|
64 |
+ port, err := strconv.Atoi(portString) |
|
65 |
+ if err != nil { |
|
66 |
+ return nil, err |
|
67 |
+ } |
|
68 |
+ |
|
69 |
+ kmaster := &MasterConfig{ |
|
70 |
+ MasterIP: net.ParseIP(host), |
|
71 |
+ MasterPort: port, |
|
72 |
+ NodeHosts: options.KubernetesMasterConfig.StaticNodeNames, |
|
73 |
+ PortalNet: &portalNet, |
|
74 |
+ RequestContextMapper: requestContextMapper, |
|
75 |
+ EtcdHelper: ketcdHelper, |
|
76 |
+ KubeClient: kubeClient, |
|
77 |
+ Authorizer: apiserver.NewAlwaysAllowAuthorizer(), |
|
78 |
+ AdmissionControl: admissionController, |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ return kmaster, nil |
|
82 |
+} |
... | ... |
@@ -2,7 +2,6 @@ package kubernetes |
2 | 2 |
|
3 | 3 |
import ( |
4 | 4 |
"crypto/tls" |
5 |
- "crypto/x509" |
|
6 | 5 |
"fmt" |
7 | 6 |
"net" |
8 | 7 |
"net/http" |
... | ... |
@@ -10,11 +9,9 @@ import ( |
10 | 10 |
"os/exec" |
11 | 11 |
"path/filepath" |
12 | 12 |
"reflect" |
13 |
- "strconv" |
|
14 | 13 |
"time" |
15 | 14 |
|
16 | 15 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
17 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
18 | 16 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" |
19 | 17 |
kconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config" |
20 | 18 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" |
... | ... |
@@ -55,44 +52,6 @@ func (ce defaultCommandExecutor) Run(command string, args ...string) error { |
55 | 55 |
return c.Run() |
56 | 56 |
} |
57 | 57 |
|
58 |
-// NodeConfig represents the required parameters to start the OpenShift node |
|
59 |
-// through Kubernetes. All fields are required. |
|
60 |
-type NodeConfig struct { |
|
61 |
- // The address to bind to |
|
62 |
- BindHost string |
|
63 |
- // The name of this node that will be used to identify the node in the master. |
|
64 |
- // This value must match the value provided to the master on startup. |
|
65 |
- NodeHost string |
|
66 |
- // The host that the master can be reached at (not in use yet) |
|
67 |
- MasterHost string |
|
68 |
- // The directory that volumes will be stored under |
|
69 |
- VolumeDir string |
|
70 |
- |
|
71 |
- ClusterDomain string |
|
72 |
- ClusterDNS net.IP |
|
73 |
- |
|
74 |
- // The image used as the Kubelet network namespace and volume container. |
|
75 |
- NetworkContainerImage string |
|
76 |
- |
|
77 |
- // If true, the Kubelet will ignore errors from Docker |
|
78 |
- AllowDisabledDocker bool |
|
79 |
- |
|
80 |
- // Whether to enable TLS serving |
|
81 |
- TLS bool |
|
82 |
- |
|
83 |
- KubeletCertFile string |
|
84 |
- KubeletKeyFile string |
|
85 |
- |
|
86 |
- // ClientCAs will be used to request client certificates in connections to the node. |
|
87 |
- // This CertPool should contain all the CAs that will be used for client certificate verification. |
|
88 |
- ClientCAs *x509.CertPool |
|
89 |
- |
|
90 |
- // A client to connect to the master. |
|
91 |
- Client *client.Client |
|
92 |
- // A client to connect to Docker |
|
93 |
- DockerClient dockertools.DockerInterface |
|
94 |
-} |
|
95 |
- |
|
96 | 58 |
// EnsureDocker attempts to connect to the Docker daemon defined by the helper, |
97 | 59 |
// and if it is unable to it will print a warning. |
98 | 60 |
func (c *NodeConfig) EnsureDocker(docker *dockerutil.Helper) { |
... | ... |
@@ -186,7 +145,7 @@ func (c *NodeConfig) RunKubelet() { |
186 | 186 |
handler := kubelet.NewServer(k, true) |
187 | 187 |
|
188 | 188 |
server := &http.Server{ |
189 |
- Addr: net.JoinHostPort(c.BindHost, strconv.Itoa(NodePort)), |
|
189 |
+ Addr: c.BindAddress, |
|
190 | 190 |
Handler: &handler, |
191 | 191 |
ReadTimeout: 5 * time.Minute, |
192 | 192 |
WriteTimeout: 5 * time.Minute, |
... | ... |
@@ -194,7 +153,7 @@ func (c *NodeConfig) RunKubelet() { |
194 | 194 |
} |
195 | 195 |
|
196 | 196 |
go util.Forever(func() { |
197 |
- glog.Infof("Started Kubelet for node %s, server at %s:%d", c.NodeHost, c.BindHost, NodePort) |
|
197 |
+ glog.Infof("Started Kubelet for node %s, server at %s", c.NodeHost, c.BindAddress) |
|
198 | 198 |
if clusterDNS != nil { |
199 | 199 |
glog.Infof(" Kubelet is setting %s as a DNS nameserver for domain %q", clusterDNS, c.ClusterDomain) |
200 | 200 |
} |
... | ... |
@@ -245,9 +204,13 @@ func (c *NodeConfig) RunProxy() { |
245 | 245 |
loadBalancer := proxy.NewLoadBalancerRR() |
246 | 246 |
endpointsConfig.RegisterHandler(loadBalancer) |
247 | 247 |
|
248 |
- ip := net.ParseIP(c.BindHost) |
|
248 |
+ host, _, err := net.SplitHostPort(c.BindAddress) |
|
249 |
+ if err != nil { |
|
250 |
+ glog.Fatalf("The provided value to bind to must be an ip:port %q", c.BindAddress) |
|
251 |
+ } |
|
252 |
+ ip := net.ParseIP(host) |
|
249 | 253 |
if ip == nil { |
250 |
- glog.Fatalf("The provided value to bind to must be an IP: %q", c.BindHost) |
|
254 |
+ glog.Fatalf("The provided value to bind to must be an ip:port: %q", c.BindAddress) |
|
251 | 255 |
} |
252 | 256 |
|
253 | 257 |
protocol := iptables.ProtocolIpv4 |
... | ... |
@@ -263,5 +226,5 @@ func (c *NodeConfig) RunProxy() { |
263 | 263 |
} |
264 | 264 |
serviceConfig.RegisterHandler(proxier) |
265 | 265 |
|
266 |
- glog.Infof("Started Kubernetes Proxy on %s", c.BindHost) |
|
266 |
+ glog.Infof("Started Kubernetes Proxy on %s", host) |
|
267 | 267 |
} |
268 | 268 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,80 @@ |
0 |
+package kubernetes |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "crypto/x509" |
|
4 |
+ "fmt" |
|
5 |
+ "net" |
|
6 |
+ |
|
7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
8 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" |
|
9 |
+ |
|
10 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+// NodeConfig represents the required parameters to start the OpenShift node |
|
14 |
+// through Kubernetes. All fields are required. |
|
15 |
+type NodeConfig struct { |
|
16 |
+ // The address to bind to |
|
17 |
+ BindAddress string |
|
18 |
+ // The name of this node that will be used to identify the node in the master. |
|
19 |
+ // This value must match the value provided to the master on startup. |
|
20 |
+ NodeHost string |
|
21 |
+ // The host that the master can be reached at (not in use yet) |
|
22 |
+ MasterHost string |
|
23 |
+ // The directory that volumes will be stored under |
|
24 |
+ VolumeDir string |
|
25 |
+ |
|
26 |
+ ClusterDomain string |
|
27 |
+ ClusterDNS net.IP |
|
28 |
+ |
|
29 |
+ // The image used as the Kubelet network namespace and volume container. |
|
30 |
+ NetworkContainerImage string |
|
31 |
+ |
|
32 |
+ // If true, the Kubelet will ignore errors from Docker |
|
33 |
+ AllowDisabledDocker bool |
|
34 |
+ |
|
35 |
+ // Whether to enable TLS serving |
|
36 |
+ TLS bool |
|
37 |
+ |
|
38 |
+ KubeletCertFile string |
|
39 |
+ KubeletKeyFile string |
|
40 |
+ |
|
41 |
+ // ClientCAs will be used to request client certificates in connections to the node. |
|
42 |
+ // This CertPool should contain all the CAs that will be used for client certificate verification. |
|
43 |
+ ClientCAs *x509.CertPool |
|
44 |
+ |
|
45 |
+ // A client to connect to the master. |
|
46 |
+ Client *client.Client |
|
47 |
+ // A client to connect to Docker |
|
48 |
+ DockerClient dockertools.DockerInterface |
|
49 |
+} |
|
50 |
+ |
|
51 |
+func BuildKubernetesNodeConfig(options configapi.NodeConfig) (*NodeConfig, error) { |
|
52 |
+ kubeClient, _, err := configapi.GetKubeClient(options.MasterKubeConfig) |
|
53 |
+ if err != nil { |
|
54 |
+ return nil, err |
|
55 |
+ } |
|
56 |
+ |
|
57 |
+ var dnsIP net.IP |
|
58 |
+ if len(options.DNSIP) > 0 { |
|
59 |
+ dnsIP = net.ParseIP(options.DNSIP) |
|
60 |
+ if dnsIP == nil { |
|
61 |
+ return nil, fmt.Errorf("Invalid DNS IP: %s", options.DNSIP) |
|
62 |
+ } |
|
63 |
+ } |
|
64 |
+ |
|
65 |
+ config := &NodeConfig{ |
|
66 |
+ NodeHost: options.NodeName, |
|
67 |
+ BindAddress: options.ServingInfo.BindAddress, |
|
68 |
+ |
|
69 |
+ ClusterDomain: options.DNSDomain, |
|
70 |
+ ClusterDNS: dnsIP, |
|
71 |
+ |
|
72 |
+ VolumeDir: options.VolumeDirectory, |
|
73 |
+ NetworkContainerImage: options.NetworkContainerImage, |
|
74 |
+ AllowDisabledDocker: options.AllowDisabledDocker, |
|
75 |
+ Client: kubeClient, |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+ return config, nil |
|
79 |
+} |
... | ... |
@@ -11,12 +11,16 @@ import ( |
11 | 11 |
) |
12 | 12 |
|
13 | 13 |
type ProxyConfig struct { |
14 |
- KubernetesAddr *url.URL |
|
15 |
- ClientConfig *kclient.Config |
|
14 |
+ ClientConfig *kclient.Config |
|
16 | 15 |
} |
17 | 16 |
|
18 | 17 |
func (c *ProxyConfig) InstallAPI(container *restful.Container) []string { |
19 |
- proxy, err := httpproxy.NewUpgradeAwareSingleHostReverseProxy(c.ClientConfig, c.KubernetesAddr) |
|
18 |
+ kubeAddr, err := url.Parse(c.ClientConfig.Host) |
|
19 |
+ if err != nil { |
|
20 |
+ glog.Fatal(err) |
|
21 |
+ } |
|
22 |
+ |
|
23 |
+ proxy, err := httpproxy.NewUpgradeAwareSingleHostReverseProxy(c.ClientConfig, kubeAddr) |
|
20 | 24 |
if err != nil { |
21 | 25 |
glog.Fatalf("Unable to initialize the Kubernetes proxy: %v", err) |
22 | 26 |
} |
23 | 27 |
deleted file mode 100644 |
... | ... |
@@ -1,46 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "net" |
|
5 |
- |
|
6 |
- "github.com/openshift/origin/pkg/cmd/server/kubernetes" |
|
7 |
-) |
|
8 |
- |
|
9 |
-func (cfg Config) BuildKubernetesNodeConfig() (*kubernetes.NodeConfig, error) { |
|
10 |
- kubernetesAddr, err := cfg.GetKubernetesAddress() |
|
11 |
- if err != nil { |
|
12 |
- return nil, err |
|
13 |
- } |
|
14 |
- kubeClient, _, err := cfg.GetKubeClient() |
|
15 |
- if err != nil { |
|
16 |
- return nil, err |
|
17 |
- } |
|
18 |
- |
|
19 |
- dnsDomain := env("OPENSHIFT_DNS_DOMAIN", "local") |
|
20 |
- dnsIP := cfg.ClusterDNS |
|
21 |
- if clusterDNS := env("OPENSHIFT_DNS_ADDR", ""); len(clusterDNS) > 0 { |
|
22 |
- dnsIP = net.ParseIP(clusterDNS) |
|
23 |
- } |
|
24 |
- |
|
25 |
- // define a function for resolving components to names |
|
26 |
- imageResolverFn := cfg.ImageTemplate.ExpandOrDie |
|
27 |
- |
|
28 |
- nodeConfig := &kubernetes.NodeConfig{ |
|
29 |
- BindHost: cfg.BindAddr.Host, |
|
30 |
- NodeHost: cfg.Hostname, |
|
31 |
- MasterHost: kubernetesAddr.String(), |
|
32 |
- |
|
33 |
- ClusterDomain: dnsDomain, |
|
34 |
- ClusterDNS: dnsIP, |
|
35 |
- |
|
36 |
- VolumeDir: cfg.VolumeDir, |
|
37 |
- |
|
38 |
- NetworkContainerImage: imageResolverFn("pod"), |
|
39 |
- |
|
40 |
- AllowDisabledDocker: cfg.StartNode && cfg.StartMaster, |
|
41 |
- |
|
42 |
- Client: kubeClient, |
|
43 |
- } |
|
44 |
- |
|
45 |
- return nodeConfig, nil |
|
46 |
-} |
... | ... |
@@ -159,72 +159,6 @@ func ParseAuthRequestHandlerTypes(types string) []AuthRequestHandlerType { |
159 | 159 |
return handlerTypes |
160 | 160 |
} |
161 | 161 |
|
162 |
-type AuthConfig struct { |
|
163 |
- // URL to call internally during token request |
|
164 |
- MasterAddr string |
|
165 |
- // URL to direct browsers to the master on |
|
166 |
- MasterPublicAddr string |
|
167 |
- // Valid redirectURI prefixes to direct browsers to the web console |
|
168 |
- AssetPublicAddresses []string |
|
169 |
- MasterRoots *x509.CertPool |
|
170 |
- EtcdHelper tools.EtcdHelper |
|
171 |
- |
|
172 |
- // Max age of authorize tokens |
|
173 |
- AuthorizeTokenMaxAgeSeconds int32 |
|
174 |
- // Max age of access tokens |
|
175 |
- AccessTokenMaxAgeSeconds int32 |
|
176 |
- |
|
177 |
- // AuthRequestHandlers contains an ordered list of authenticators that decide if a request is authenticated |
|
178 |
- AuthRequestHandlers []AuthRequestHandlerType |
|
179 |
- |
|
180 |
- // AuthHandler specifies what handles unauthenticated requests |
|
181 |
- AuthHandler AuthHandlerType |
|
182 |
- |
|
183 |
- // GrantHandler specifies what handles requests for new client authorizations |
|
184 |
- GrantHandler GrantHandlerType |
|
185 |
- |
|
186 |
- // PasswordAuth specifies how to validate username/passwords. Used by AuthRequestHandlerBasicAuth and AuthHandlerLogin |
|
187 |
- PasswordAuth PasswordAuthType |
|
188 |
- // BasicAuthURL specifies the remote URL to validate username/passwords against using basic auth. Used by PasswordAuthBasicAuthURL. |
|
189 |
- BasicAuthURL string |
|
190 |
- // HTPasswdFile specifies the path to an htpasswd file to validate username/passwords against. Used by PasswordAuthHTPasswd. |
|
191 |
- HTPasswdFile string |
|
192 |
- |
|
193 |
- // TokenStore specifies how to validate bearer tokens. Used by AuthRequestHandlerBearer. |
|
194 |
- TokenStore TokenStoreType |
|
195 |
- // TokenFilePath is a path to a CSV file to load valid tokens from. Used by TokenStoreFile. |
|
196 |
- TokenFilePath string |
|
197 |
- |
|
198 |
- // RequestHeaders lists the headers to check (in order) for a username. Used by AuthRequestHandlerRequestHeader |
|
199 |
- RequestHeaders []string |
|
200 |
- // RequestHeaderCAFile specifies the path to a PEM-encoded certificate bundle. |
|
201 |
- // If set, a client certificate must be presented and validate against the CA before the request headers are checked for usernames |
|
202 |
- RequestHeaderCAFile string |
|
203 |
- |
|
204 |
- // SessionSecrets list the secret(s) to use to encrypt created sessions. Used by AuthRequestHandlerSession |
|
205 |
- SessionSecrets []string |
|
206 |
- // SessionMaxAgeSeconds specifies how long created sessions last. Used by AuthRequestHandlerSession |
|
207 |
- SessionMaxAgeSeconds int32 |
|
208 |
- // SessionName is the cookie name used to store the session |
|
209 |
- SessionName string |
|
210 |
- // sessionAuth holds the Authenticator built from the exported Session* options. It should only be accessed via getSessionAuth(), since it is lazily built. |
|
211 |
- sessionAuth *session.Authenticator |
|
212 |
- |
|
213 |
- // GoogleClientID is the client_id of a client registered with the Google OAuth provider. |
|
214 |
- // It must be authorized to redirect to {MasterPublicAddr}/oauth2callback/google |
|
215 |
- // Used by AuthHandlerGoogle |
|
216 |
- GoogleClientID string |
|
217 |
- // GoogleClientID is the client_secret of a client registered with the Google OAuth provider. |
|
218 |
- GoogleClientSecret string |
|
219 |
- |
|
220 |
- // GithubClientID is the client_id of a client registered with the GitHub OAuth provider. |
|
221 |
- // It must be authorized to redirect to {MasterPublicAddr}/oauth2callback/github |
|
222 |
- // Used by AuthHandlerGithub |
|
223 |
- GithubClientID string |
|
224 |
- // GithubClientID is the client_secret of a client registered with the GitHub OAuth provider. |
|
225 |
- GithubClientSecret string |
|
226 |
-} |
|
227 |
- |
|
228 | 162 |
// InstallSupport registers endpoints for an OAuth2 server into the provided mux, |
229 | 163 |
// then returns an array of strings indicating what endpoints were started |
230 | 164 |
// (these are format strings that will expect to be sent a single string value). |
231 | 165 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,144 @@ |
0 |
+package origin |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "crypto/x509" |
|
4 |
+ "fmt" |
|
5 |
+ "strings" |
|
6 |
+ |
|
7 |
+ "code.google.com/p/go-uuid/uuid" |
|
8 |
+ |
|
9 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
10 |
+ |
|
11 |
+ "github.com/openshift/origin/pkg/auth/server/session" |
|
12 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
13 |
+ "github.com/openshift/origin/pkg/cmd/server/etcd" |
|
14 |
+ cmdutil "github.com/openshift/origin/pkg/cmd/util" |
|
15 |
+) |
|
16 |
+ |
|
17 |
+type AuthConfig struct { |
|
18 |
+ // URL to call internally during token request |
|
19 |
+ MasterAddr string |
|
20 |
+ // URL to direct browsers to the master on |
|
21 |
+ MasterPublicAddr string |
|
22 |
+ // Valid redirectURI prefixes to direct browsers to the web console |
|
23 |
+ AssetPublicAddresses []string |
|
24 |
+ MasterRoots *x509.CertPool |
|
25 |
+ EtcdHelper tools.EtcdHelper |
|
26 |
+ |
|
27 |
+ // Max age of authorize tokens |
|
28 |
+ AuthorizeTokenMaxAgeSeconds int32 |
|
29 |
+ // Max age of access tokens |
|
30 |
+ AccessTokenMaxAgeSeconds int32 |
|
31 |
+ |
|
32 |
+ // AuthRequestHandlers contains an ordered list of authenticators that decide if a request is authenticated |
|
33 |
+ AuthRequestHandlers []AuthRequestHandlerType |
|
34 |
+ |
|
35 |
+ // AuthHandler specifies what handles unauthenticated requests |
|
36 |
+ AuthHandler AuthHandlerType |
|
37 |
+ |
|
38 |
+ // GrantHandler specifies what handles requests for new client authorizations |
|
39 |
+ GrantHandler GrantHandlerType |
|
40 |
+ |
|
41 |
+ // PasswordAuth specifies how to validate username/passwords. Used by AuthRequestHandlerBasicAuth and AuthHandlerLogin |
|
42 |
+ PasswordAuth PasswordAuthType |
|
43 |
+ // BasicAuthURL specifies the remote URL to validate username/passwords against using basic auth. Used by PasswordAuthBasicAuthURL. |
|
44 |
+ BasicAuthURL string |
|
45 |
+ // HTPasswdFile specifies the path to an htpasswd file to validate username/passwords against. Used by PasswordAuthHTPasswd. |
|
46 |
+ HTPasswdFile string |
|
47 |
+ |
|
48 |
+ // TokenStore specifies how to validate bearer tokens. Used by AuthRequestHandlerBearer. |
|
49 |
+ TokenStore TokenStoreType |
|
50 |
+ // TokenFilePath is a path to a CSV file to load valid tokens from. Used by TokenStoreFile. |
|
51 |
+ TokenFilePath string |
|
52 |
+ |
|
53 |
+ // RequestHeaders lists the headers to check (in order) for a username. Used by AuthRequestHandlerRequestHeader |
|
54 |
+ RequestHeaders []string |
|
55 |
+ // RequestHeaderCAFile specifies the path to a PEM-encoded certificate bundle. |
|
56 |
+ // If set, a client certificate must be presented and validate against the CA before the request headers are checked for usernames |
|
57 |
+ RequestHeaderCAFile string |
|
58 |
+ |
|
59 |
+ // SessionSecrets list the secret(s) to use to encrypt created sessions. Used by AuthRequestHandlerSession |
|
60 |
+ SessionSecrets []string |
|
61 |
+ // SessionMaxAgeSeconds specifies how long created sessions last. Used by AuthRequestHandlerSession |
|
62 |
+ SessionMaxAgeSeconds int32 |
|
63 |
+ // SessionName is the cookie name used to store the session |
|
64 |
+ SessionName string |
|
65 |
+ // sessionAuth holds the Authenticator built from the exported Session* options. It should only be accessed via getSessionAuth(), since it is lazily built. |
|
66 |
+ sessionAuth *session.Authenticator |
|
67 |
+ |
|
68 |
+ // GoogleClientID is the client_id of a client registered with the Google OAuth provider. |
|
69 |
+ // It must be authorized to redirect to {MasterPublicAddr}/oauth2callback/google |
|
70 |
+ // Used by AuthHandlerGoogle |
|
71 |
+ GoogleClientID string |
|
72 |
+ // GoogleClientID is the client_secret of a client registered with the Google OAuth provider. |
|
73 |
+ GoogleClientSecret string |
|
74 |
+ |
|
75 |
+ // GithubClientID is the client_id of a client registered with the GitHub OAuth provider. |
|
76 |
+ // It must be authorized to redirect to {MasterPublicAddr}/oauth2callback/github |
|
77 |
+ // Used by AuthHandlerGithub |
|
78 |
+ GithubClientID string |
|
79 |
+ // GithubClientID is the client_secret of a client registered with the GitHub OAuth provider. |
|
80 |
+ GithubClientSecret string |
|
81 |
+} |
|
82 |
+ |
|
83 |
+func BuildAuthConfig(options configapi.MasterConfig) (*AuthConfig, error) { |
|
84 |
+ etcdHelper, err := etcd.NewOpenShiftEtcdHelper(options.EtcdClientInfo.URL) |
|
85 |
+ if err != nil { |
|
86 |
+ return nil, fmt.Errorf("Error setting up server storage: %v", err) |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ apiServerCAs, err := configapi.GetAPIServerCertCAPool(options) |
|
90 |
+ if err != nil { |
|
91 |
+ return nil, err |
|
92 |
+ } |
|
93 |
+ |
|
94 |
+ // Build the list of valid redirect_uri prefixes for a login using the openshift-web-console client to redirect to |
|
95 |
+ // TODO: allow configuring this |
|
96 |
+ // TODO: remove hard-coding of development UI server |
|
97 |
+ assetPublicURLs := []string{options.OAuthConfig.AssetPublicURL, "http://localhost:9000", "https://localhost:9000"} |
|
98 |
+ |
|
99 |
+ // Default to a session authenticator (for browsers), and a basicauth authenticator (for clients responding to WWW-Authenticate challenges) |
|
100 |
+ defaultAuthRequestHandlers := strings.Join([]string{ |
|
101 |
+ string(AuthRequestHandlerSession), |
|
102 |
+ string(AuthRequestHandlerBasicAuth), |
|
103 |
+ }, ",") |
|
104 |
+ |
|
105 |
+ ret := &AuthConfig{ |
|
106 |
+ MasterAddr: options.OAuthConfig.MasterURL, |
|
107 |
+ MasterPublicAddr: options.OAuthConfig.MasterPublicURL, |
|
108 |
+ AssetPublicAddresses: assetPublicURLs, |
|
109 |
+ MasterRoots: apiServerCAs, |
|
110 |
+ EtcdHelper: etcdHelper, |
|
111 |
+ |
|
112 |
+ // Max token ages |
|
113 |
+ AuthorizeTokenMaxAgeSeconds: cmdutil.EnvInt("OPENSHIFT_OAUTH_AUTHORIZE_TOKEN_MAX_AGE_SECONDS", 300, 1), |
|
114 |
+ AccessTokenMaxAgeSeconds: cmdutil.EnvInt("OPENSHIFT_OAUTH_ACCESS_TOKEN_MAX_AGE_SECONDS", 3600, 1), |
|
115 |
+ // Handlers |
|
116 |
+ AuthRequestHandlers: ParseAuthRequestHandlerTypes(cmdutil.Env("OPENSHIFT_OAUTH_REQUEST_HANDLERS", defaultAuthRequestHandlers)), |
|
117 |
+ AuthHandler: AuthHandlerType(cmdutil.Env("OPENSHIFT_OAUTH_HANDLER", string(AuthHandlerLogin))), |
|
118 |
+ GrantHandler: GrantHandlerType(cmdutil.Env("OPENSHIFT_OAUTH_GRANT_HANDLER", string(GrantHandlerAuto))), |
|
119 |
+ // RequestHeader config |
|
120 |
+ RequestHeaders: strings.Split(cmdutil.Env("OPENSHIFT_OAUTH_REQUEST_HEADERS", "X-Remote-User"), ","), |
|
121 |
+ RequestHeaderCAFile: options.OAuthConfig.ProxyCA, |
|
122 |
+ // Session config (default to unknowable secret) |
|
123 |
+ SessionSecrets: []string{cmdutil.Env("OPENSHIFT_OAUTH_SESSION_SECRET", uuid.NewUUID().String())}, |
|
124 |
+ SessionMaxAgeSeconds: cmdutil.EnvInt("OPENSHIFT_OAUTH_SESSION_MAX_AGE_SECONDS", 300, 1), |
|
125 |
+ SessionName: cmdutil.Env("OPENSHIFT_OAUTH_SESSION_NAME", "ssn"), |
|
126 |
+ // Password config |
|
127 |
+ PasswordAuth: PasswordAuthType(cmdutil.Env("OPENSHIFT_OAUTH_PASSWORD_AUTH", string(PasswordAuthAnyPassword))), |
|
128 |
+ BasicAuthURL: cmdutil.Env("OPENSHIFT_OAUTH_BASIC_AUTH_URL", ""), |
|
129 |
+ HTPasswdFile: cmdutil.Env("OPENSHIFT_OAUTH_HTPASSWD_FILE", ""), |
|
130 |
+ // Token config |
|
131 |
+ TokenStore: TokenStoreType(cmdutil.Env("OPENSHIFT_OAUTH_TOKEN_STORE", string(TokenStoreOAuth))), |
|
132 |
+ TokenFilePath: cmdutil.Env("OPENSHIFT_OAUTH_TOKEN_FILE_PATH", ""), |
|
133 |
+ // Google config |
|
134 |
+ GoogleClientID: cmdutil.Env("OPENSHIFT_OAUTH_GOOGLE_CLIENT_ID", ""), |
|
135 |
+ GoogleClientSecret: cmdutil.Env("OPENSHIFT_OAUTH_GOOGLE_CLIENT_SECRET", ""), |
|
136 |
+ // GitHub config |
|
137 |
+ GithubClientID: cmdutil.Env("OPENSHIFT_OAUTH_GITHUB_CLIENT_ID", ""), |
|
138 |
+ GithubClientSecret: cmdutil.Env("OPENSHIFT_OAUTH_GITHUB_CLIENT_SECRET", ""), |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ return ret, nil |
|
142 |
+ |
|
143 |
+} |
0 | 144 |
deleted file mode 100644 |
... | ... |
@@ -1,212 +0,0 @@ |
1 |
-package origin |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "crypto/x509" |
|
5 |
- "net/http" |
|
6 |
- "strings" |
|
7 |
- |
|
8 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" |
|
9 |
- kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
10 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" |
|
11 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
|
12 |
- kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
13 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
14 |
- kutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
15 |
- |
|
16 |
- "github.com/openshift/origin/pkg/api/latest" |
|
17 |
- "github.com/openshift/origin/pkg/auth/authenticator" |
|
18 |
- "github.com/openshift/origin/pkg/auth/authenticator/request/bearertoken" |
|
19 |
- "github.com/openshift/origin/pkg/auth/authenticator/request/paramtoken" |
|
20 |
- "github.com/openshift/origin/pkg/auth/authenticator/request/unionrequest" |
|
21 |
- "github.com/openshift/origin/pkg/auth/authenticator/request/x509request" |
|
22 |
- "github.com/openshift/origin/pkg/auth/group" |
|
23 |
- authnregistry "github.com/openshift/origin/pkg/auth/oauth/registry" |
|
24 |
- "github.com/openshift/origin/pkg/authorization/authorizer" |
|
25 |
- policycache "github.com/openshift/origin/pkg/authorization/cache" |
|
26 |
- authorizationetcd "github.com/openshift/origin/pkg/authorization/registry/etcd" |
|
27 |
- "github.com/openshift/origin/pkg/authorization/rulevalidation" |
|
28 |
- osclient "github.com/openshift/origin/pkg/client" |
|
29 |
- oauthetcd "github.com/openshift/origin/pkg/oauth/registry/etcd" |
|
30 |
- projectauth "github.com/openshift/origin/pkg/project/auth" |
|
31 |
-) |
|
32 |
- |
|
33 |
-const ( |
|
34 |
- unauthenticatedUsername = "system:anonymous" |
|
35 |
- |
|
36 |
- authenticatedGroup = "system:authenticated" |
|
37 |
- unauthenticatedGroup = "system:unauthenticated" |
|
38 |
-) |
|
39 |
- |
|
40 |
-type MasterConfigParameters struct { |
|
41 |
- // host:port to bind master to |
|
42 |
- MasterBindAddr string |
|
43 |
- // host:port to bind asset server to |
|
44 |
- AssetBindAddr string |
|
45 |
- // url to access the master API on within the cluster |
|
46 |
- MasterAddr string |
|
47 |
- // url to access kubernetes API on within the cluster |
|
48 |
- KubernetesAddr string |
|
49 |
- // external clients may need to access APIs at different addresses than internal components do |
|
50 |
- MasterPublicAddr string |
|
51 |
- KubernetesPublicAddr string |
|
52 |
- AssetPublicAddr string |
|
53 |
- // host:port to bind DNS on. The default is port 53. |
|
54 |
- DNSBindAddr string |
|
55 |
- // LogoutURI is an optional, absolute URI to redirect web browsers to after logging out of the web console. |
|
56 |
- // If not specified, the built-in logout page is shown. |
|
57 |
- LogoutURI string |
|
58 |
- |
|
59 |
- CORSAllowedOrigins []string |
|
60 |
- |
|
61 |
- EtcdHelper tools.EtcdHelper |
|
62 |
- |
|
63 |
- MasterCertFile string |
|
64 |
- MasterKeyFile string |
|
65 |
- AssetCertFile string |
|
66 |
- AssetKeyFile string |
|
67 |
- |
|
68 |
- // ClientCAs will be used to request client certificates in connections to the API or OAuth server. |
|
69 |
- // This CertPool should contain all the CAs that will be used for client certificate verification (the union |
|
70 |
- // of APIClientCAs and OAuthClientCAs). |
|
71 |
- ClientCAs *x509.CertPool |
|
72 |
- // APIClientCAs is used to verify client certificates presented for API auth |
|
73 |
- APIClientCAs *x509.CertPool |
|
74 |
- |
|
75 |
- MasterAuthorizationNamespace string |
|
76 |
- OpenshiftSharedResourcesNamespace string |
|
77 |
- |
|
78 |
- // a function that returns the appropriate image to use for a named component |
|
79 |
- ImageFor func(component string) string |
|
80 |
- |
|
81 |
- // kubeClient is the client used to call Kubernetes APIs from system components, built from KubeClientConfig. |
|
82 |
- // It should only be accessed via the *Client() helper methods. |
|
83 |
- // To apply different access control to a system component, create a separate client/config specifically for that component. |
|
84 |
- KubeClient *kclient.Client |
|
85 |
- // KubeClientConfig is the client configuration used to call Kubernetes APIs from system components. |
|
86 |
- // To apply different access control to a system component, create a client config specifically for that component. |
|
87 |
- KubeClientConfig kclient.Config |
|
88 |
- |
|
89 |
- // osClient is the client used to call OpenShift APIs from system components, built from OSClientConfig. |
|
90 |
- // It should only be accessed via the *Client() helper methods. |
|
91 |
- // To apply different access control to a system component, create a separate client/config specifically for that component. |
|
92 |
- OSClient *osclient.Client |
|
93 |
- // OSClientConfig is the client configuration used to call OpenShift APIs from system components |
|
94 |
- // To apply different access control to a system component, create a client config specifically for that component. |
|
95 |
- OSClientConfig kclient.Config |
|
96 |
- |
|
97 |
- // DeployerOSClientConfig is the client configuration used to call OpenShift APIs from launched deployer pods |
|
98 |
- DeployerOSClientConfig kclient.Config |
|
99 |
-} |
|
100 |
- |
|
101 |
-// MasterConfig defines the required parameters for starting the OpenShift master |
|
102 |
-type MasterConfig struct { |
|
103 |
- MasterConfigParameters |
|
104 |
- |
|
105 |
- Authenticator authenticator.Request |
|
106 |
- Authorizer authorizer.Authorizer |
|
107 |
- AuthorizationAttributeBuilder authorizer.AuthorizationAttributeBuilder |
|
108 |
- |
|
109 |
- PolicyCache *policycache.PolicyCache |
|
110 |
- ProjectAuthorizationCache *projectauth.AuthorizationCache |
|
111 |
- |
|
112 |
- // Map requests to contexts |
|
113 |
- RequestContextMapper kapi.RequestContextMapper |
|
114 |
- |
|
115 |
- AdmissionControl admission.Interface |
|
116 |
- |
|
117 |
- TLS bool |
|
118 |
-} |
|
119 |
- |
|
120 |
-func BuildMasterConfig(configParams MasterConfigParameters) (*MasterConfig, error) { |
|
121 |
- |
|
122 |
- policyCache := configParams.newPolicyCache() |
|
123 |
- requestContextMapper := kapi.NewRequestContextMapper() |
|
124 |
- |
|
125 |
- // in-order list of plug-ins that should intercept admission decisions (origin only intercepts) |
|
126 |
- admissionControlPluginNames := []string{"AlwaysAdmit"} |
|
127 |
- admissionController := admission.NewFromPlugins(configParams.KubeClient, admissionControlPluginNames, "") |
|
128 |
- |
|
129 |
- config := &MasterConfig{ |
|
130 |
- MasterConfigParameters: configParams, |
|
131 |
- |
|
132 |
- Authenticator: configParams.newAuthenticator(), |
|
133 |
- Authorizer: newAuthorizer(policyCache, configParams.MasterAuthorizationNamespace), |
|
134 |
- AuthorizationAttributeBuilder: newAuthorizationAttributeBuilder(requestContextMapper), |
|
135 |
- |
|
136 |
- PolicyCache: policyCache, |
|
137 |
- ProjectAuthorizationCache: configParams.newProjectAuthorizationCache(), |
|
138 |
- |
|
139 |
- RequestContextMapper: requestContextMapper, |
|
140 |
- |
|
141 |
- AdmissionControl: admissionController, |
|
142 |
- |
|
143 |
- TLS: strings.HasPrefix(configParams.MasterAddr, "https://"), |
|
144 |
- } |
|
145 |
- |
|
146 |
- return config, nil |
|
147 |
-} |
|
148 |
- |
|
149 |
-func (c MasterConfigParameters) newAuthenticator() authenticator.Request { |
|
150 |
- useTLS := strings.HasPrefix(c.MasterAddr, "https://") |
|
151 |
- |
|
152 |
- tokenAuthenticator := getEtcdTokenAuthenticator(c.EtcdHelper) |
|
153 |
- |
|
154 |
- authenticators := []authenticator.Request{} |
|
155 |
- authenticators = append(authenticators, bearertoken.New(tokenAuthenticator, true)) |
|
156 |
- // Allow token as access_token param for WebSockets |
|
157 |
- // TODO: make the param name configurable |
|
158 |
- // TODO: limit this authenticator to watch methods, if possible |
|
159 |
- // TODO: prevent access_token param from getting logged, if possible |
|
160 |
- authenticators = append(authenticators, paramtoken.New("access_token", tokenAuthenticator, true)) |
|
161 |
- |
|
162 |
- if useTLS { |
|
163 |
- // build cert authenticator |
|
164 |
- // TODO: add cert users to etcd? |
|
165 |
- opts := x509request.DefaultVerifyOptions() |
|
166 |
- opts.Roots = c.APIClientCAs |
|
167 |
- certauth := x509request.New(opts, x509request.SubjectToUserConversion) |
|
168 |
- authenticators = append(authenticators, certauth) |
|
169 |
- } |
|
170 |
- |
|
171 |
- // TODO: make anonymous auth optional? |
|
172 |
- ret := &unionrequest.Authenticator{ |
|
173 |
- FailOnError: true, |
|
174 |
- Handlers: []authenticator.Request{ |
|
175 |
- group.NewGroupAdder(unionrequest.NewUnionAuthentication(authenticators...), []string{authenticatedGroup}), |
|
176 |
- authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) { |
|
177 |
- return &user.DefaultInfo{Name: unauthenticatedUsername, Groups: []string{unauthenticatedGroup}}, true, nil |
|
178 |
- }), |
|
179 |
- }, |
|
180 |
- } |
|
181 |
- |
|
182 |
- return ret |
|
183 |
-} |
|
184 |
- |
|
185 |
-func (c MasterConfigParameters) newProjectAuthorizationCache() *projectauth.AuthorizationCache { |
|
186 |
- return projectauth.NewAuthorizationCache( |
|
187 |
- projectauth.NewReviewer(c.OSClient), |
|
188 |
- c.KubeClient.Namespaces(), |
|
189 |
- c.OSClient, |
|
190 |
- c.OSClient, |
|
191 |
- c.MasterAuthorizationNamespace) |
|
192 |
-} |
|
193 |
- |
|
194 |
-func (c MasterConfigParameters) newPolicyCache() *policycache.PolicyCache { |
|
195 |
- authorizationEtcd := authorizationetcd.New(c.EtcdHelper) |
|
196 |
- return policycache.NewPolicyCache(authorizationEtcd, authorizationEtcd) |
|
197 |
-} |
|
198 |
- |
|
199 |
-func newAuthorizer(policyCache *policycache.PolicyCache, masterAuthorizationNamespace string) authorizer.Authorizer { |
|
200 |
- authorizer := authorizer.NewAuthorizer(masterAuthorizationNamespace, rulevalidation.NewDefaultRuleResolver(policyCache, policyCache)) |
|
201 |
- return authorizer |
|
202 |
-} |
|
203 |
- |
|
204 |
-func newAuthorizationAttributeBuilder(requestContextMapper kapi.RequestContextMapper) authorizer.AuthorizationAttributeBuilder { |
|
205 |
- authorizationAttributeBuilder := authorizer.NewAuthorizationAttributeBuilder(requestContextMapper, &apiserver.APIRequestInfoResolver{kutil.NewStringSet("api", "osapi"), latest.RESTMapper}) |
|
206 |
- return authorizationAttributeBuilder |
|
207 |
-} |
|
208 |
- |
|
209 |
-func getEtcdTokenAuthenticator(etcdHelper tools.EtcdHelper) authenticator.Token { |
|
210 |
- oauthRegistry := oauthetcd.New(etcdHelper) |
|
211 |
- return authnregistry.NewTokenAuthenticator(oauthRegistry) |
|
212 |
-} |
... | ... |
@@ -86,6 +86,7 @@ import ( |
86 | 86 |
roleregistry "github.com/openshift/origin/pkg/authorization/registry/role" |
87 | 87 |
rolebindingregistry "github.com/openshift/origin/pkg/authorization/registry/rolebinding" |
88 | 88 |
subjectaccessreviewregistry "github.com/openshift/origin/pkg/authorization/registry/subjectaccessreview" |
89 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
89 | 90 |
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" |
90 | 91 |
routeplugin "github.com/openshift/origin/plugins/route/allocation/simple" |
91 | 92 |
) |
... | ... |
@@ -114,7 +115,7 @@ func (fn APIInstallFunc) InstallAPI(container *restful.Container) []string { |
114 | 114 |
|
115 | 115 |
// KubeClient returns the kubernetes client object |
116 | 116 |
func (c *MasterConfig) KubeClient() *kclient.Client { |
117 |
- return c.MasterConfigParameters.KubeClient |
|
117 |
+ return c.KubernetesClient |
|
118 | 118 |
} |
119 | 119 |
|
120 | 120 |
// PolicyClient returns the policy client object |
... | ... |
@@ -128,19 +129,19 @@ func (c *MasterConfig) PolicyClient() *osclient.Client { |
128 | 128 |
|
129 | 129 |
// DeploymentClient returns the deployment client object |
130 | 130 |
func (c *MasterConfig) DeploymentClient() *kclient.Client { |
131 |
- return c.MasterConfigParameters.KubeClient |
|
131 |
+ return c.KubernetesClient |
|
132 | 132 |
} |
133 | 133 |
|
134 | 134 |
// DNSServerClient returns the DNS server client object |
135 | 135 |
// It must have the following capabilities: |
136 | 136 |
// list, watch all services in all namespaces |
137 | 137 |
func (c *MasterConfig) DNSServerClient() *kclient.Client { |
138 |
- return c.MasterConfigParameters.KubeClient |
|
138 |
+ return c.KubernetesClient |
|
139 | 139 |
} |
140 | 140 |
|
141 | 141 |
// BuildLogClient returns the build log client object |
142 | 142 |
func (c *MasterConfig) BuildLogClient() *kclient.Client { |
143 |
- return c.MasterConfigParameters.KubeClient |
|
143 |
+ return c.KubernetesClient |
|
144 | 144 |
} |
145 | 145 |
|
146 | 146 |
// WebHookClient returns the webhook client object |
... | ... |
@@ -150,7 +151,7 @@ func (c *MasterConfig) WebHookClient() *osclient.Client { |
150 | 150 |
|
151 | 151 |
// BuildControllerClients returns the build controller client objects |
152 | 152 |
func (c *MasterConfig) BuildControllerClients() (*osclient.Client, *kclient.Client) { |
153 |
- return c.OSClient, c.MasterConfigParameters.KubeClient |
|
153 |
+ return c.OSClient, c.KubernetesClient |
|
154 | 154 |
} |
155 | 155 |
|
156 | 156 |
// ImageChangeControllerClient returns the openshift client object |
... | ... |
@@ -160,7 +161,7 @@ func (c *MasterConfig) ImageChangeControllerClient() *osclient.Client { |
160 | 160 |
|
161 | 161 |
// DeploymentControllerClients returns the deployment controller client object |
162 | 162 |
func (c *MasterConfig) DeploymentControllerClients() (*osclient.Client, *kclient.Client) { |
163 |
- return c.OSClient, c.MasterConfigParameters.KubeClient |
|
163 |
+ return c.OSClient, c.KubernetesClient |
|
164 | 164 |
} |
165 | 165 |
|
166 | 166 |
// DeployerClientConfig returns the client configuration a Deployer instance launched in a pod |
... | ... |
@@ -170,10 +171,10 @@ func (c *MasterConfig) DeployerClientConfig() *kclient.Config { |
170 | 170 |
} |
171 | 171 |
|
172 | 172 |
func (c *MasterConfig) DeploymentConfigControllerClients() (*osclient.Client, *kclient.Client) { |
173 |
- return c.OSClient, c.MasterConfigParameters.KubeClient |
|
173 |
+ return c.OSClient, c.KubernetesClient |
|
174 | 174 |
} |
175 | 175 |
func (c *MasterConfig) DeploymentConfigChangeControllerClients() (*osclient.Client, *kclient.Client) { |
176 |
- return c.OSClient, c.MasterConfigParameters.KubeClient |
|
176 |
+ return c.OSClient, c.KubernetesClient |
|
177 | 177 |
} |
178 | 178 |
func (c *MasterConfig) DeploymentImageChangeControllerClient() *osclient.Client { |
179 | 179 |
return c.OSClient |
... | ... |
@@ -258,7 +259,7 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin |
258 | 258 |
"policies": policyregistry.NewREST(authorizationEtcd), |
259 | 259 |
"policyBindings": policybindingregistry.NewREST(authorizationEtcd), |
260 | 260 |
"roles": roleregistry.NewREST(roleregistry.NewVirtualRegistry(authorizationEtcd)), |
261 |
- "roleBindings": rolebindingregistry.NewREST(rolebindingregistry.NewVirtualRegistry(authorizationEtcd, authorizationEtcd, c.MasterAuthorizationNamespace)), |
|
261 |
+ "roleBindings": rolebindingregistry.NewREST(rolebindingregistry.NewVirtualRegistry(authorizationEtcd, authorizationEtcd, c.Options.MasterAuthorizationNamespace)), |
|
262 | 262 |
"resourceAccessReviews": resourceaccessreviewregistry.NewREST(c.Authorizer), |
263 | 263 |
"subjectAccessReviews": subjectaccessreviewregistry.NewREST(c.Authorizer), |
264 | 264 |
} |
... | ... |
@@ -365,7 +366,7 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) |
365 | 365 |
} |
366 | 366 |
|
367 | 367 |
server := &http.Server{ |
368 |
- Addr: c.MasterBindAddr, |
|
368 |
+ Addr: c.Options.ServingInfo.BindAddress, |
|
369 | 369 |
Handler: handler, |
370 | 370 |
ReadTimeout: 5 * time.Minute, |
371 | 371 |
WriteTimeout: 5 * time.Minute, |
... | ... |
@@ -374,7 +375,7 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) |
374 | 374 |
|
375 | 375 |
go util.Forever(func() { |
376 | 376 |
for _, s := range extra { |
377 |
- glog.Infof(s, c.MasterAddr) |
|
377 |
+ glog.Infof(s, c.Options.ServingInfo.BindAddress) |
|
378 | 378 |
} |
379 | 379 |
if c.TLS { |
380 | 380 |
server.TLSConfig = &tls.Config{ |
... | ... |
@@ -385,14 +386,14 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) |
385 | 385 |
ClientAuth: tls.RequestClientCert, |
386 | 386 |
ClientCAs: c.ClientCAs, |
387 | 387 |
} |
388 |
- glog.Fatal(server.ListenAndServeTLS(c.MasterCertFile, c.MasterKeyFile)) |
|
388 |
+ glog.Fatal(server.ListenAndServeTLS(c.Options.ServingInfo.ServerCert.CertFile, c.Options.ServingInfo.ServerCert.KeyFile)) |
|
389 | 389 |
} else { |
390 | 390 |
glog.Fatal(server.ListenAndServe()) |
391 | 391 |
} |
392 | 392 |
}, 0) |
393 | 393 |
|
394 | 394 |
// Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try) |
395 |
- cmdutil.WaitForSuccessfulDial(c.TLS, "tcp", c.MasterBindAddr, 100*time.Millisecond, 100*time.Millisecond, 100) |
|
395 |
+ cmdutil.WaitForSuccessfulDial(c.TLS, "tcp", c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) |
|
396 | 396 |
|
397 | 397 |
// Attempt to create the required policy rules now, and then stick in a forever loop to make sure they are always available |
398 | 398 |
c.ensureComponentAuthorizationRules() |
... | ... |
@@ -415,9 +416,9 @@ func (c *MasterConfig) getRequestContextMapper() kapi.RequestContextMapper { |
415 | 415 |
func (c *MasterConfig) ensureMasterAuthorizationNamespace() { |
416 | 416 |
|
417 | 417 |
// ensure that master namespace actually exists |
418 |
- namespace, err := c.KubeClient().Namespaces().Get(c.MasterAuthorizationNamespace) |
|
418 |
+ namespace, err := c.KubeClient().Namespaces().Get(c.Options.MasterAuthorizationNamespace) |
|
419 | 419 |
if err != nil { |
420 |
- namespace = &kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: c.MasterAuthorizationNamespace}} |
|
420 |
+ namespace = &kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: c.Options.MasterAuthorizationNamespace}} |
|
421 | 421 |
kapi.FillObjectMetaSystemFields(api.NewContext(), &namespace.ObjectMeta) |
422 | 422 |
_, err = c.KubeClient().Namespaces().Create(namespace) |
423 | 423 |
if err != nil { |
... | ... |
@@ -431,7 +432,7 @@ func (c *MasterConfig) ensureComponentAuthorizationRules() { |
431 | 431 |
registry := authorizationetcd.New(c.EtcdHelper) |
432 | 432 |
|
433 | 433 |
roleRegistry := roleregistry.NewVirtualRegistry(registry) |
434 |
- for _, role := range bootstrappolicy.GetBootstrapRoles(c.MasterAuthorizationNamespace, c.OpenshiftSharedResourcesNamespace) { |
|
434 |
+ for _, role := range bootstrappolicy.GetBootstrapRoles(c.Options.MasterAuthorizationNamespace, c.Options.OpenShiftSharedResourcesNamespace) { |
|
435 | 435 |
ctx := kapi.WithNamespace(kapi.NewContext(), role.Namespace) |
436 | 436 |
|
437 | 437 |
if _, err := roleRegistry.GetRole(ctx, role.Name); kapierror.IsNotFound(err) { |
... | ... |
@@ -444,13 +445,13 @@ func (c *MasterConfig) ensureComponentAuthorizationRules() { |
444 | 444 |
} |
445 | 445 |
} |
446 | 446 |
|
447 |
- roleBindingRegistry := rolebindingregistry.NewVirtualRegistry(registry, registry, c.MasterAuthorizationNamespace) |
|
448 |
- for _, roleBinding := range bootstrappolicy.GetBootstrapRoleBindings(c.MasterAuthorizationNamespace, c.OpenshiftSharedResourcesNamespace) { |
|
447 |
+ roleBindingRegistry := rolebindingregistry.NewVirtualRegistry(registry, registry, c.Options.MasterAuthorizationNamespace) |
|
448 |
+ for _, roleBinding := range bootstrappolicy.GetBootstrapRoleBindings(c.Options.MasterAuthorizationNamespace, c.Options.OpenShiftSharedResourcesNamespace) { |
|
449 | 449 |
ctx := kapi.WithNamespace(kapi.NewContext(), roleBinding.Namespace) |
450 | 450 |
|
451 | 451 |
if _, err := roleBindingRegistry.GetRoleBinding(ctx, roleBinding.Name); kapierror.IsNotFound(err) { |
452 | 452 |
// if this is a binding for a non-master namespaced role. That means that the policy binding must be provisioned |
453 |
- if roleBinding.RoleRef.Namespace != c.MasterAuthorizationNamespace { |
|
453 |
+ if roleBinding.RoleRef.Namespace != c.Options.MasterAuthorizationNamespace { |
|
454 | 454 |
policyBindingName := roleBinding.RoleRef.Namespace |
455 | 455 |
if _, err := registry.GetPolicyBinding(ctx, policyBindingName); kapierror.IsNotFound(err) { |
456 | 456 |
policyBinding := &authorizationapi.PolicyBinding{ |
... | ... |
@@ -540,12 +541,12 @@ func (c *MasterConfig) RunAssetServer() { |
540 | 540 |
// TODO use version.Get().GitCommit as an etag cache header |
541 | 541 |
mux := http.NewServeMux() |
542 | 542 |
|
543 |
- masterURL, err := url.Parse(c.MasterPublicAddr) |
|
543 |
+ masterURL, err := url.Parse(c.Options.AssetConfig.MasterPublicURL) |
|
544 | 544 |
if err != nil { |
545 | 545 |
glog.Fatalf("Error parsing master url: %v", err) |
546 | 546 |
} |
547 | 547 |
|
548 |
- k8sURL, err := url.Parse(c.KubernetesPublicAddr) |
|
548 |
+ k8sURL, err := url.Parse(c.Options.AssetConfig.KubernetesPublicURL) |
|
549 | 549 |
if err != nil { |
550 | 550 |
glog.Fatalf("Error parsing kubernetes url: %v", err) |
551 | 551 |
} |
... | ... |
@@ -556,9 +557,9 @@ func (c *MasterConfig) RunAssetServer() { |
556 | 556 |
KubernetesAddr: k8sURL.Host, |
557 | 557 |
KubernetesPrefix: "/api", |
558 | 558 |
OAuthAuthorizeURI: OpenShiftOAuthAuthorizeURL(masterURL.String()), |
559 |
- OAuthRedirectBase: c.AssetPublicAddr, |
|
559 |
+ OAuthRedirectBase: c.Options.AssetConfig.PublicURL, |
|
560 | 560 |
OAuthClientID: OpenShiftWebConsoleClientID, |
561 |
- LogoutURI: c.LogoutURI, |
|
561 |
+ LogoutURI: c.Options.AssetConfig.LogoutURI, |
|
562 | 562 |
} |
563 | 563 |
|
564 | 564 |
assets.RegisterMimeTypes() |
... | ... |
@@ -588,7 +589,7 @@ func (c *MasterConfig) RunAssetServer() { |
588 | 588 |
) |
589 | 589 |
|
590 | 590 |
server := &http.Server{ |
591 |
- Addr: c.AssetBindAddr, |
|
591 |
+ Addr: c.Options.AssetConfig.ServingInfo.BindAddress, |
|
592 | 592 |
Handler: mux, |
593 | 593 |
ReadTimeout: 5 * time.Minute, |
594 | 594 |
WriteTimeout: 5 * time.Minute, |
... | ... |
@@ -601,18 +602,18 @@ func (c *MasterConfig) RunAssetServer() { |
601 | 601 |
// Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability) |
602 | 602 |
MinVersion: tls.VersionTLS10, |
603 | 603 |
} |
604 |
- glog.Infof("OpenShift UI listening at https://%s", c.AssetBindAddr) |
|
605 |
- glog.Fatal(server.ListenAndServeTLS(c.AssetCertFile, c.AssetKeyFile)) |
|
604 |
+ glog.Infof("OpenShift UI listening at https://%s", c.Options.AssetConfig.ServingInfo.BindAddress) |
|
605 |
+ glog.Fatal(server.ListenAndServeTLS(c.Options.AssetConfig.ServingInfo.ServerCert.CertFile, c.Options.AssetConfig.ServingInfo.ServerCert.KeyFile)) |
|
606 | 606 |
} else { |
607 |
- glog.Infof("OpenShift UI listening at https://%s", c.AssetBindAddr) |
|
607 |
+ glog.Infof("OpenShift UI listening at https://%s", c.Options.AssetConfig.ServingInfo.BindAddress) |
|
608 | 608 |
glog.Fatal(server.ListenAndServe()) |
609 | 609 |
} |
610 | 610 |
}, 0) |
611 | 611 |
|
612 | 612 |
// Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try) |
613 |
- cmdutil.WaitForSuccessfulDial(c.TLS, "tcp", c.AssetBindAddr, 100*time.Millisecond, 100*time.Millisecond, 100) |
|
613 |
+ cmdutil.WaitForSuccessfulDial(c.TLS, "tcp", c.Options.AssetConfig.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) |
|
614 | 614 |
|
615 |
- glog.Infof("OpenShift UI available at %s", c.AssetPublicAddr) |
|
615 |
+ glog.Infof("OpenShift UI available at %s", c.Options.AssetConfig.PublicURL) |
|
616 | 616 |
} |
617 | 617 |
|
618 | 618 |
func (c *MasterConfig) RunDNSServer() { |
... | ... |
@@ -620,22 +621,29 @@ func (c *MasterConfig) RunDNSServer() { |
620 | 620 |
if err != nil { |
621 | 621 |
glog.Fatalf("Could not start DNS: %v", err) |
622 | 622 |
} |
623 |
+ config.DnsAddr = c.Options.DNSConfig.BindAddress |
|
623 | 624 |
|
624 |
- if _, port, err := net.SplitHostPort(c.DNSBindAddr); err == nil { |
|
625 |
- if len(port) != 0 && port != "53" { |
|
626 |
- glog.Warningf("Unable to bind DNS on port 53 (you may need to run as root), using %s which will not resolve from all locations", c.DNSBindAddr) |
|
627 |
- } |
|
625 |
+ _, port, err := net.SplitHostPort(c.Options.DNSConfig.BindAddress) |
|
626 |
+ if err != nil { |
|
627 |
+ glog.Fatalf("Could not start DNS: %v", err) |
|
628 |
+ } |
|
629 |
+ if port != "53" { |
|
630 |
+ glog.Warningf("Binding DNS on port %v instead of 53 (you may need to run as root and update your config), using %s which will not resolve from all locations", port, c.Options.DNSConfig.BindAddress) |
|
631 |
+ } |
|
632 |
+ |
|
633 |
+ if ok, err := cmdutil.TryListen(c.Options.DNSConfig.BindAddress); !ok { |
|
634 |
+ glog.Warningf("Could not start DNS: %v", err) |
|
635 |
+ return |
|
628 | 636 |
} |
629 | 637 |
|
630 |
- config.DnsAddr = c.DNSBindAddr |
|
631 | 638 |
go func() { |
632 | 639 |
err := dns.ListenAndServe(config, c.DNSServerClient(), c.EtcdHelper.Client.(*etcdclient.Client)) |
633 | 640 |
glog.Fatalf("Could not start DNS: %v", err) |
634 | 641 |
}() |
635 | 642 |
|
636 |
- cmdutil.WaitForSuccessfulDial(false, "tcp", c.DNSBindAddr, 100*time.Millisecond, 100*time.Millisecond, 100) |
|
643 |
+ cmdutil.WaitForSuccessfulDial(false, "tcp", c.Options.DNSConfig.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) |
|
637 | 644 |
|
638 |
- glog.Infof("OpenShift DNS listening at %s", c.DNSBindAddr) |
|
645 |
+ glog.Infof("OpenShift DNS listening at %s", c.Options.DNSConfig.BindAddress) |
|
639 | 646 |
} |
640 | 647 |
|
641 | 648 |
// RunBuildController starts the build sync loop for builds and buildConfig processing. |
... | ... |
@@ -682,7 +690,7 @@ func (c *MasterConfig) RunBuildPodController() { |
682 | 682 |
controller.Run() |
683 | 683 |
} |
684 | 684 |
|
685 |
-// RunDeploymentController starts the build image change trigger controller process. |
|
685 |
+// RunBuildImageChangeTriggerController starts the build image change trigger controller process. |
|
686 | 686 |
func (c *MasterConfig) RunBuildImageChangeTriggerController() { |
687 | 687 |
bcClient, _ := c.BuildControllerClients() |
688 | 688 |
bcUpdater := buildclient.NewOSClientBuildConfigClient(bcClient) |
... | ... |
@@ -692,11 +700,17 @@ func (c *MasterConfig) RunBuildImageChangeTriggerController() { |
692 | 692 |
} |
693 | 693 |
|
694 | 694 |
// RunDeploymentController starts the deployment controller process. |
695 |
-func (c *MasterConfig) RunDeploymentController() { |
|
695 |
+func (c *MasterConfig) RunDeploymentController() error { |
|
696 | 696 |
_, kclient := c.DeploymentControllerClients() |
697 |
+ |
|
698 |
+ _, kclientConfig, err := configapi.GetKubeClient(c.Options.MasterClients.OpenShiftLoopbackKubeConfig) |
|
699 |
+ if err != nil { |
|
700 |
+ return err |
|
701 |
+ } |
|
702 |
+ // TODO eliminate these environment variables once we figure out what they do |
|
697 | 703 |
env := []api.EnvVar{ |
698 |
- {Name: "KUBERNETES_MASTER", Value: c.MasterAddr}, |
|
699 |
- {Name: "OPENSHIFT_MASTER", Value: c.MasterAddr}, |
|
704 |
+ {Name: "KUBERNETES_MASTER", Value: kclientConfig.Host}, |
|
705 |
+ {Name: "OPENSHIFT_MASTER", Value: kclientConfig.Host}, |
|
700 | 706 |
} |
701 | 707 |
env = append(env, clientcmd.EnvVarsFromConfig(c.DeployerClientConfig())...) |
702 | 708 |
|
... | ... |
@@ -709,6 +723,8 @@ func (c *MasterConfig) RunDeploymentController() { |
709 | 709 |
|
710 | 710 |
controller := factory.Create() |
711 | 711 |
controller.Run() |
712 |
+ |
|
713 |
+ return nil |
|
712 | 714 |
} |
713 | 715 |
|
714 | 716 |
// RunDeployerPodController starts the deployer pod controller process. |
... | ... |
@@ -774,10 +790,10 @@ func (c *MasterConfig) RouteAllocator() *routeallocationcontroller.RouteAllocati |
774 | 774 |
// ensureCORSAllowedOrigins takes a string list of origins and attempts to covert them to CORS origin |
775 | 775 |
// regexes, or exits if it cannot. |
776 | 776 |
func (c *MasterConfig) ensureCORSAllowedOrigins() []*regexp.Regexp { |
777 |
- if len(c.CORSAllowedOrigins) == 0 { |
|
777 |
+ if len(c.Options.CORSAllowedOrigins) == 0 { |
|
778 | 778 |
return []*regexp.Regexp{} |
779 | 779 |
} |
780 |
- allowedOriginRegexps, err := util.CompileRegexps(util.StringList(c.CORSAllowedOrigins)) |
|
780 |
+ allowedOriginRegexps, err := util.CompileRegexps(util.StringList(c.Options.CORSAllowedOrigins)) |
|
781 | 781 |
if err != nil { |
782 | 782 |
glog.Fatalf("Invalid --cors-allowed-origins: %v", err) |
783 | 783 |
} |
784 | 784 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,225 @@ |
0 |
+package origin |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "crypto/x509" |
|
4 |
+ "fmt" |
|
5 |
+ "net/http" |
|
6 |
+ |
|
7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" |
|
8 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
9 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" |
|
10 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
|
11 |
+ kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
12 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" |
|
13 |
+ kutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
14 |
+ |
|
15 |
+ "github.com/openshift/origin/pkg/api/latest" |
|
16 |
+ "github.com/openshift/origin/pkg/auth/authenticator" |
|
17 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/bearertoken" |
|
18 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/paramtoken" |
|
19 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/unionrequest" |
|
20 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/x509request" |
|
21 |
+ "github.com/openshift/origin/pkg/auth/group" |
|
22 |
+ authnregistry "github.com/openshift/origin/pkg/auth/oauth/registry" |
|
23 |
+ "github.com/openshift/origin/pkg/authorization/authorizer" |
|
24 |
+ policycache "github.com/openshift/origin/pkg/authorization/cache" |
|
25 |
+ authorizationetcd "github.com/openshift/origin/pkg/authorization/registry/etcd" |
|
26 |
+ "github.com/openshift/origin/pkg/authorization/rulevalidation" |
|
27 |
+ osclient "github.com/openshift/origin/pkg/client" |
|
28 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
29 |
+ oauthetcd "github.com/openshift/origin/pkg/oauth/registry/etcd" |
|
30 |
+ projectauth "github.com/openshift/origin/pkg/project/auth" |
|
31 |
+ |
|
32 |
+ "github.com/openshift/origin/pkg/cmd/server/etcd" |
|
33 |
+ "github.com/openshift/origin/pkg/cmd/util/variable" |
|
34 |
+) |
|
35 |
+ |
|
36 |
+const ( |
|
37 |
+ unauthenticatedUsername = "system:anonymous" |
|
38 |
+ |
|
39 |
+ authenticatedGroup = "system:authenticated" |
|
40 |
+ unauthenticatedGroup = "system:unauthenticated" |
|
41 |
+) |
|
42 |
+ |
|
43 |
+// MasterConfig defines the required parameters for starting the OpenShift master |
|
44 |
+type MasterConfig struct { |
|
45 |
+ Options configapi.MasterConfig |
|
46 |
+ |
|
47 |
+ Authenticator authenticator.Request |
|
48 |
+ Authorizer authorizer.Authorizer |
|
49 |
+ AuthorizationAttributeBuilder authorizer.AuthorizationAttributeBuilder |
|
50 |
+ |
|
51 |
+ PolicyCache *policycache.PolicyCache |
|
52 |
+ ProjectAuthorizationCache *projectauth.AuthorizationCache |
|
53 |
+ |
|
54 |
+ // Map requests to contexts |
|
55 |
+ RequestContextMapper kapi.RequestContextMapper |
|
56 |
+ |
|
57 |
+ AdmissionControl admission.Interface |
|
58 |
+ |
|
59 |
+ TLS bool |
|
60 |
+ |
|
61 |
+ // a function that returns the appropriate image to use for a named component |
|
62 |
+ ImageFor func(component string) string |
|
63 |
+ |
|
64 |
+ EtcdHelper tools.EtcdHelper |
|
65 |
+ |
|
66 |
+ // ClientCAs will be used to request client certificates in connections to the API. |
|
67 |
+ // This CertPool should contain all the CAs that will be used for client certificate verification. |
|
68 |
+ ClientCAs *x509.CertPool |
|
69 |
+ // APIClientCAs is used to verify client certificates presented for API auth |
|
70 |
+ APIClientCAs *x509.CertPool |
|
71 |
+ |
|
72 |
+ // KubeClientConfig is the client configuration used to call Kubernetes APIs from system components. |
|
73 |
+ // To apply different access control to a system component, create a client config specifically for that component. |
|
74 |
+ KubeClientConfig kclient.Config |
|
75 |
+ // OSClientConfig is the client configuration used to call OpenShift APIs from system components |
|
76 |
+ // To apply different access control to a system component, create a client config specifically for that component. |
|
77 |
+ OSClientConfig kclient.Config |
|
78 |
+ // DeployerOSClientConfig is the client configuration used to call OpenShift APIs from launched deployer pods |
|
79 |
+ DeployerOSClientConfig kclient.Config |
|
80 |
+ |
|
81 |
+ // kubeClient is the client used to call Kubernetes APIs from system components, built from KubeClientConfig. |
|
82 |
+ // It should only be accessed via the *Client() helper methods. |
|
83 |
+ // To apply different access control to a system component, create a separate client/config specifically for that component. |
|
84 |
+ KubernetesClient *kclient.Client |
|
85 |
+ // osClient is the client used to call OpenShift APIs from system components, built from OSClientConfig. |
|
86 |
+ // It should only be accessed via the *Client() helper methods. |
|
87 |
+ // To apply different access control to a system component, create a separate client/config specifically for that component. |
|
88 |
+ OSClient *osclient.Client |
|
89 |
+} |
|
90 |
+ |
|
91 |
+func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) { |
|
92 |
+ |
|
93 |
+ etcdHelper, err := etcd.NewOpenShiftEtcdHelper(options.EtcdClientInfo.URL) |
|
94 |
+ if err != nil { |
|
95 |
+ return nil, fmt.Errorf("Error setting up server storage: %v", err) |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ clientCAs, err := configapi.GetClientCertCAPool(options) |
|
99 |
+ if err != nil { |
|
100 |
+ return nil, err |
|
101 |
+ } |
|
102 |
+ apiClientCAs, err := configapi.GetAPIClientCertCAPool(options) |
|
103 |
+ if err != nil { |
|
104 |
+ return nil, err |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ kubeClient, kubeClientConfig, err := configapi.GetKubeClient(options.MasterClients.KubernetesKubeConfig) |
|
108 |
+ if err != nil { |
|
109 |
+ return nil, err |
|
110 |
+ } |
|
111 |
+ openshiftClient, osClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.OpenShiftLoopbackKubeConfig) |
|
112 |
+ if err != nil { |
|
113 |
+ return nil, err |
|
114 |
+ } |
|
115 |
+ _, deployerOSClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.DeployerKubeConfig) |
|
116 |
+ if err != nil { |
|
117 |
+ return nil, err |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ imageTemplate := variable.NewDefaultImageTemplate() |
|
121 |
+ imageTemplate.Format = options.ImageConfig.Format |
|
122 |
+ imageTemplate.Latest = options.ImageConfig.Latest |
|
123 |
+ |
|
124 |
+ policyCache := newPolicyCache(etcdHelper) |
|
125 |
+ requestContextMapper := kapi.NewRequestContextMapper() |
|
126 |
+ |
|
127 |
+ // in-order list of plug-ins that should intercept admission decisions (origin only intercepts) |
|
128 |
+ admissionControlPluginNames := []string{"AlwaysAdmit"} |
|
129 |
+ admissionController := admission.NewFromPlugins(kubeClient, admissionControlPluginNames, "") |
|
130 |
+ |
|
131 |
+ config := &MasterConfig{ |
|
132 |
+ Options: options, |
|
133 |
+ |
|
134 |
+ Authenticator: newAuthenticator(options.ServingInfo, etcdHelper, apiClientCAs), |
|
135 |
+ Authorizer: newAuthorizer(policyCache, options.MasterAuthorizationNamespace), |
|
136 |
+ AuthorizationAttributeBuilder: newAuthorizationAttributeBuilder(requestContextMapper), |
|
137 |
+ |
|
138 |
+ PolicyCache: policyCache, |
|
139 |
+ ProjectAuthorizationCache: newProjectAuthorizationCache(options.MasterAuthorizationNamespace, openshiftClient, kubeClient), |
|
140 |
+ |
|
141 |
+ RequestContextMapper: requestContextMapper, |
|
142 |
+ |
|
143 |
+ AdmissionControl: admissionController, |
|
144 |
+ |
|
145 |
+ TLS: configapi.UseTLS(options.ServingInfo), |
|
146 |
+ |
|
147 |
+ ImageFor: imageTemplate.ExpandOrDie, |
|
148 |
+ EtcdHelper: etcdHelper, |
|
149 |
+ |
|
150 |
+ ClientCAs: clientCAs, |
|
151 |
+ APIClientCAs: apiClientCAs, |
|
152 |
+ |
|
153 |
+ KubeClientConfig: *kubeClientConfig, |
|
154 |
+ OSClientConfig: *osClientConfig, |
|
155 |
+ DeployerOSClientConfig: *deployerOSClientConfig, |
|
156 |
+ OSClient: openshiftClient, |
|
157 |
+ KubernetesClient: kubeClient, |
|
158 |
+ } |
|
159 |
+ |
|
160 |
+ return config, nil |
|
161 |
+} |
|
162 |
+ |
|
163 |
+func newAuthenticator(servingInfo configapi.ServingInfo, etcdHelper tools.EtcdHelper, apiClientCAs *x509.CertPool) authenticator.Request { |
|
164 |
+ tokenAuthenticator := getEtcdTokenAuthenticator(etcdHelper) |
|
165 |
+ |
|
166 |
+ authenticators := []authenticator.Request{} |
|
167 |
+ authenticators = append(authenticators, bearertoken.New(tokenAuthenticator, true)) |
|
168 |
+ // Allow token as access_token param for WebSockets |
|
169 |
+ // TODO: make the param name configurable |
|
170 |
+ // TODO: limit this authenticator to watch methods, if possible |
|
171 |
+ // TODO: prevent access_token param from getting logged, if possible |
|
172 |
+ authenticators = append(authenticators, paramtoken.New("access_token", tokenAuthenticator, true)) |
|
173 |
+ |
|
174 |
+ if configapi.UseTLS(servingInfo) { |
|
175 |
+ // build cert authenticator |
|
176 |
+ // TODO: add cert users to etcd? |
|
177 |
+ opts := x509request.DefaultVerifyOptions() |
|
178 |
+ opts.Roots = apiClientCAs |
|
179 |
+ certauth := x509request.New(opts, x509request.SubjectToUserConversion) |
|
180 |
+ authenticators = append(authenticators, certauth) |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ // TODO: make anonymous auth optional? |
|
184 |
+ ret := &unionrequest.Authenticator{ |
|
185 |
+ FailOnError: true, |
|
186 |
+ Handlers: []authenticator.Request{ |
|
187 |
+ group.NewGroupAdder(unionrequest.NewUnionAuthentication(authenticators...), []string{authenticatedGroup}), |
|
188 |
+ authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) { |
|
189 |
+ return &user.DefaultInfo{Name: unauthenticatedUsername, Groups: []string{unauthenticatedGroup}}, true, nil |
|
190 |
+ }), |
|
191 |
+ }, |
|
192 |
+ } |
|
193 |
+ |
|
194 |
+ return ret |
|
195 |
+} |
|
196 |
+ |
|
197 |
+func newProjectAuthorizationCache(masterAuthorizationNamespace string, openshiftClient *osclient.Client, kubeClient *kclient.Client) *projectauth.AuthorizationCache { |
|
198 |
+ return projectauth.NewAuthorizationCache( |
|
199 |
+ projectauth.NewReviewer(openshiftClient), |
|
200 |
+ kubeClient.Namespaces(), |
|
201 |
+ openshiftClient, |
|
202 |
+ openshiftClient, |
|
203 |
+ masterAuthorizationNamespace) |
|
204 |
+} |
|
205 |
+ |
|
206 |
+func newPolicyCache(etcdHelper tools.EtcdHelper) *policycache.PolicyCache { |
|
207 |
+ authorizationEtcd := authorizationetcd.New(etcdHelper) |
|
208 |
+ return policycache.NewPolicyCache(authorizationEtcd, authorizationEtcd) |
|
209 |
+} |
|
210 |
+ |
|
211 |
+func newAuthorizer(policyCache *policycache.PolicyCache, masterAuthorizationNamespace string) authorizer.Authorizer { |
|
212 |
+ authorizer := authorizer.NewAuthorizer(masterAuthorizationNamespace, rulevalidation.NewDefaultRuleResolver(policyCache, policyCache)) |
|
213 |
+ return authorizer |
|
214 |
+} |
|
215 |
+ |
|
216 |
+func newAuthorizationAttributeBuilder(requestContextMapper kapi.RequestContextMapper) authorizer.AuthorizationAttributeBuilder { |
|
217 |
+ authorizationAttributeBuilder := authorizer.NewAuthorizationAttributeBuilder(requestContextMapper, &apiserver.APIRequestInfoResolver{kutil.NewStringSet("api", "osapi"), latest.RESTMapper}) |
|
218 |
+ return authorizationAttributeBuilder |
|
219 |
+} |
|
220 |
+ |
|
221 |
+func getEtcdTokenAuthenticator(etcdHelper tools.EtcdHelper) authenticator.Token { |
|
222 |
+ oauthRegistry := oauthetcd.New(etcdHelper) |
|
223 |
+ return authnregistry.NewTokenAuthenticator(oauthRegistry) |
|
224 |
+} |
0 | 225 |
deleted file mode 100644 |
... | ... |
@@ -1,506 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "crypto/x509" |
|
5 |
- "fmt" |
|
6 |
- "io/ioutil" |
|
7 |
- "net" |
|
8 |
- "strings" |
|
9 |
- "time" |
|
10 |
- |
|
11 |
- "code.google.com/p/go-uuid/uuid" |
|
12 |
- |
|
13 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
|
14 |
- kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
15 |
- clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" |
|
16 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
17 |
- |
|
18 |
- osclient "github.com/openshift/origin/pkg/client" |
|
19 |
- "github.com/openshift/origin/pkg/cmd/server/crypto" |
|
20 |
- "github.com/openshift/origin/pkg/cmd/server/origin" |
|
21 |
- cmdutil "github.com/openshift/origin/pkg/cmd/util" |
|
22 |
-) |
|
23 |
- |
|
24 |
-func (cfg Config) BuildOriginMasterConfig() (*origin.MasterConfig, error) { |
|
25 |
- masterAddr, err := cfg.GetMasterAddress() |
|
26 |
- if err != nil { |
|
27 |
- return nil, err |
|
28 |
- } |
|
29 |
- kubeAddr, err := cfg.GetKubernetesAddress() |
|
30 |
- if err != nil { |
|
31 |
- return nil, err |
|
32 |
- } |
|
33 |
- masterPublicAddr, err := cfg.GetMasterPublicAddress() |
|
34 |
- if err != nil { |
|
35 |
- return nil, err |
|
36 |
- } |
|
37 |
- kubePublicAddr, err := cfg.GetKubernetesPublicAddress() |
|
38 |
- if err != nil { |
|
39 |
- return nil, err |
|
40 |
- } |
|
41 |
- assetPublicAddr, err := cfg.GetAssetPublicAddress() |
|
42 |
- if err != nil { |
|
43 |
- return nil, err |
|
44 |
- } |
|
45 |
- |
|
46 |
- corsAllowedOrigins := []string{} |
|
47 |
- corsAllowedOrigins = append(corsAllowedOrigins, cfg.CORSAllowedOrigins...) |
|
48 |
- // always include the all-in-one server's web console as an allowed CORS origin |
|
49 |
- // always include localhost as an allowed CORS origin |
|
50 |
- // always include master public address as an allowed CORS origin |
|
51 |
- for _, origin := range []string{assetPublicAddr.Host, masterPublicAddr.Host, "localhost", "127.0.0.1"} { |
|
52 |
- // TODO: check if origin is already allowed |
|
53 |
- corsAllowedOrigins = append(corsAllowedOrigins, origin) |
|
54 |
- } |
|
55 |
- |
|
56 |
- etcdHelper, err := cfg.newOpenShiftEtcdHelper() |
|
57 |
- if err != nil { |
|
58 |
- return nil, fmt.Errorf("Error setting up server storage: %v", err) |
|
59 |
- } |
|
60 |
- |
|
61 |
- masterCertFile, masterKeyFile, err := cfg.GetMasterCert() |
|
62 |
- if err != nil { |
|
63 |
- return nil, err |
|
64 |
- } |
|
65 |
- assetCertFile, assetKeyFile, err := cfg.GetAssetCert() |
|
66 |
- if err != nil { |
|
67 |
- return nil, err |
|
68 |
- } |
|
69 |
- |
|
70 |
- clientCAs, err := cfg.GetClientCertCAPool() |
|
71 |
- if err != nil { |
|
72 |
- return nil, err |
|
73 |
- } |
|
74 |
- apiClientCAs, err := cfg.GetAPIClientCertCAPool() |
|
75 |
- if err != nil { |
|
76 |
- return nil, err |
|
77 |
- } |
|
78 |
- |
|
79 |
- kubeClient, kubeClientConfig, err := cfg.GetKubeClient() |
|
80 |
- if err != nil { |
|
81 |
- return nil, err |
|
82 |
- } |
|
83 |
- openshiftClient, openshiftClientConfig, err := cfg.GetOpenshiftClient() |
|
84 |
- if err != nil { |
|
85 |
- return nil, err |
|
86 |
- } |
|
87 |
- deployerClientConfig, err := cfg.GetOpenshiftDeployerClientConfig() |
|
88 |
- if err != nil { |
|
89 |
- return nil, err |
|
90 |
- } |
|
91 |
- |
|
92 |
- dnsAddr := cfg.DNSBindAddr |
|
93 |
- if !cmdutil.TryListen(dnsAddr.URL.Host) { |
|
94 |
- dnsAddr.DefaultPort = 8053 |
|
95 |
- dnsAddr = dnsAddr.Default() |
|
96 |
- } |
|
97 |
- |
|
98 |
- openshiftConfigParameters := origin.MasterConfigParameters{ |
|
99 |
- MasterBindAddr: cfg.BindAddr.URL.Host, |
|
100 |
- AssetBindAddr: cfg.GetAssetBindAddress(), |
|
101 |
- DNSBindAddr: dnsAddr.URL.Host, |
|
102 |
- MasterAddr: masterAddr.String(), |
|
103 |
- KubernetesAddr: kubeAddr.String(), |
|
104 |
- MasterPublicAddr: masterPublicAddr.String(), |
|
105 |
- KubernetesPublicAddr: kubePublicAddr.String(), |
|
106 |
- AssetPublicAddr: assetPublicAddr.String(), |
|
107 |
- |
|
108 |
- CORSAllowedOrigins: corsAllowedOrigins, |
|
109 |
- MasterAuthorizationNamespace: "master", |
|
110 |
- OpenshiftSharedResourcesNamespace: "openshift", |
|
111 |
- LogoutURI: env("OPENSHIFT_LOGOUT_URI", ""), |
|
112 |
- |
|
113 |
- EtcdHelper: etcdHelper, |
|
114 |
- |
|
115 |
- MasterCertFile: masterCertFile, |
|
116 |
- MasterKeyFile: masterKeyFile, |
|
117 |
- AssetCertFile: assetCertFile, |
|
118 |
- AssetKeyFile: assetKeyFile, |
|
119 |
- ClientCAs: clientCAs, |
|
120 |
- APIClientCAs: apiClientCAs, |
|
121 |
- |
|
122 |
- KubeClient: kubeClient, |
|
123 |
- KubeClientConfig: *kubeClientConfig, |
|
124 |
- OSClient: openshiftClient, |
|
125 |
- OSClientConfig: *openshiftClientConfig, |
|
126 |
- DeployerOSClientConfig: *deployerClientConfig, |
|
127 |
- |
|
128 |
- ImageFor: cfg.ImageTemplate.ExpandOrDie, |
|
129 |
- } |
|
130 |
- openshiftConfig, err := origin.BuildMasterConfig(openshiftConfigParameters) |
|
131 |
- if err != nil { |
|
132 |
- return nil, err |
|
133 |
- } |
|
134 |
- |
|
135 |
- return openshiftConfig, nil |
|
136 |
-} |
|
137 |
- |
|
138 |
-func (cfg Config) BuildAuthConfig() (*origin.AuthConfig, error) { |
|
139 |
- masterAddr, err := cfg.GetMasterAddress() |
|
140 |
- if err != nil { |
|
141 |
- return nil, err |
|
142 |
- } |
|
143 |
- masterPublicAddr, err := cfg.GetMasterPublicAddress() |
|
144 |
- if err != nil { |
|
145 |
- return nil, err |
|
146 |
- } |
|
147 |
- assetPublicAddr, err := cfg.GetAssetPublicAddress() |
|
148 |
- if err != nil { |
|
149 |
- return nil, err |
|
150 |
- } |
|
151 |
- |
|
152 |
- apiServerCAs, err := cfg.GetAPIServerCertCAPool() |
|
153 |
- if err != nil { |
|
154 |
- return nil, err |
|
155 |
- } |
|
156 |
- |
|
157 |
- // Build the list of valid redirect_uri prefixes for a login using the openshift-web-console client to redirect to |
|
158 |
- // TODO: allow configuring this |
|
159 |
- // TODO: remove hard-coding of development UI server |
|
160 |
- assetPublicAddresses := []string{assetPublicAddr.String(), "http://localhost:9000", "https://localhost:9000"} |
|
161 |
- |
|
162 |
- etcdHelper, err := cfg.newOpenShiftEtcdHelper() |
|
163 |
- if err != nil { |
|
164 |
- return nil, fmt.Errorf("Error setting up server storage: %v", err) |
|
165 |
- } |
|
166 |
- // Default to a session authenticator (for browsers), and a basicauth authenticator (for clients responding to WWW-Authenticate challenges) |
|
167 |
- defaultAuthRequestHandlers := strings.Join([]string{ |
|
168 |
- string(origin.AuthRequestHandlerSession), |
|
169 |
- string(origin.AuthRequestHandlerBasicAuth), |
|
170 |
- }, ",") |
|
171 |
- |
|
172 |
- ret := &origin.AuthConfig{ |
|
173 |
- MasterAddr: masterAddr.String(), |
|
174 |
- MasterPublicAddr: masterPublicAddr.String(), |
|
175 |
- AssetPublicAddresses: assetPublicAddresses, |
|
176 |
- MasterRoots: apiServerCAs, |
|
177 |
- EtcdHelper: etcdHelper, |
|
178 |
- |
|
179 |
- // Max token ages |
|
180 |
- AuthorizeTokenMaxAgeSeconds: envInt("OPENSHIFT_OAUTH_AUTHORIZE_TOKEN_MAX_AGE_SECONDS", 300, 1), |
|
181 |
- AccessTokenMaxAgeSeconds: envInt("OPENSHIFT_OAUTH_ACCESS_TOKEN_MAX_AGE_SECONDS", 3600, 1), |
|
182 |
- // Handlers |
|
183 |
- AuthRequestHandlers: origin.ParseAuthRequestHandlerTypes(env("OPENSHIFT_OAUTH_REQUEST_HANDLERS", defaultAuthRequestHandlers)), |
|
184 |
- AuthHandler: origin.AuthHandlerType(env("OPENSHIFT_OAUTH_HANDLER", string(origin.AuthHandlerLogin))), |
|
185 |
- GrantHandler: origin.GrantHandlerType(env("OPENSHIFT_OAUTH_GRANT_HANDLER", string(origin.GrantHandlerAuto))), |
|
186 |
- // RequestHeader config |
|
187 |
- RequestHeaders: strings.Split(env("OPENSHIFT_OAUTH_REQUEST_HEADERS", "X-Remote-User"), ","), |
|
188 |
- RequestHeaderCAFile: GetOAuthRequestHeaderCAFile(), |
|
189 |
- // Session config (default to unknowable secret) |
|
190 |
- SessionSecrets: []string{env("OPENSHIFT_OAUTH_SESSION_SECRET", uuid.NewUUID().String())}, |
|
191 |
- SessionMaxAgeSeconds: envInt("OPENSHIFT_OAUTH_SESSION_MAX_AGE_SECONDS", 300, 1), |
|
192 |
- SessionName: env("OPENSHIFT_OAUTH_SESSION_NAME", "ssn"), |
|
193 |
- // Password config |
|
194 |
- PasswordAuth: origin.PasswordAuthType(env("OPENSHIFT_OAUTH_PASSWORD_AUTH", string(origin.PasswordAuthAnyPassword))), |
|
195 |
- BasicAuthURL: env("OPENSHIFT_OAUTH_BASIC_AUTH_URL", ""), |
|
196 |
- HTPasswdFile: env("OPENSHIFT_OAUTH_HTPASSWD_FILE", ""), |
|
197 |
- // Token config |
|
198 |
- TokenStore: origin.TokenStoreType(env("OPENSHIFT_OAUTH_TOKEN_STORE", string(origin.TokenStoreOAuth))), |
|
199 |
- TokenFilePath: env("OPENSHIFT_OAUTH_TOKEN_FILE_PATH", ""), |
|
200 |
- // Google config |
|
201 |
- GoogleClientID: env("OPENSHIFT_OAUTH_GOOGLE_CLIENT_ID", ""), |
|
202 |
- GoogleClientSecret: env("OPENSHIFT_OAUTH_GOOGLE_CLIENT_SECRET", ""), |
|
203 |
- // GitHub config |
|
204 |
- GithubClientID: env("OPENSHIFT_OAUTH_GITHUB_CLIENT_ID", ""), |
|
205 |
- GithubClientSecret: env("OPENSHIFT_OAUTH_GITHUB_CLIENT_SECRET", ""), |
|
206 |
- } |
|
207 |
- |
|
208 |
- return ret, nil |
|
209 |
- |
|
210 |
-} |
|
211 |
- |
|
212 |
-func GetOAuthRequestHeaderCAFile() string { |
|
213 |
- return env("OPENSHIFT_OAUTH_REQUEST_HEADER_CA_FILE", "") |
|
214 |
-} |
|
215 |
- |
|
216 |
-func (cfg Config) newCA() (*crypto.CA, error) { |
|
217 |
- masterAddr, err := cfg.GetMasterAddress() |
|
218 |
- if err != nil { |
|
219 |
- return nil, err |
|
220 |
- } |
|
221 |
- |
|
222 |
- // Bootstrap CA |
|
223 |
- // TODO: store this (or parts of this) in etcd? |
|
224 |
- ca, err := crypto.InitCA(cfg.CertDir, fmt.Sprintf("%s@%d", masterAddr.Host, time.Now().Unix())) |
|
225 |
- if err != nil { |
|
226 |
- return nil, fmt.Errorf("Unable to configure certificate authority: %v", err) |
|
227 |
- } |
|
228 |
- |
|
229 |
- return ca, nil |
|
230 |
-} |
|
231 |
- |
|
232 |
-// GetAPIClientCertCAPool returns the cert pool used to validate client certificates to the API server |
|
233 |
-func (cfg Config) GetAPIClientCertCAPool() (*x509.CertPool, error) { |
|
234 |
- certs, err := cfg.getAPIClientCertCAs() |
|
235 |
- if err != nil { |
|
236 |
- return nil, err |
|
237 |
- } |
|
238 |
- roots := x509.NewCertPool() |
|
239 |
- for _, root := range certs { |
|
240 |
- roots.AddCert(root) |
|
241 |
- } |
|
242 |
- return roots, nil |
|
243 |
-} |
|
244 |
- |
|
245 |
-// GetClientCertCAPool returns a cert pool containing all client CAs that could be presented (union of API and OAuth) |
|
246 |
-func (cfg Config) GetClientCertCAPool() (*x509.CertPool, error) { |
|
247 |
- roots := x509.NewCertPool() |
|
248 |
- |
|
249 |
- // Add CAs for OAuth |
|
250 |
- certs, err := cfg.getOAuthClientCertCAs() |
|
251 |
- if err != nil { |
|
252 |
- return nil, err |
|
253 |
- } |
|
254 |
- for _, root := range certs { |
|
255 |
- roots.AddCert(root) |
|
256 |
- } |
|
257 |
- |
|
258 |
- // Add CAs for API |
|
259 |
- certs, err = cfg.getAPIClientCertCAs() |
|
260 |
- if err != nil { |
|
261 |
- return nil, err |
|
262 |
- } |
|
263 |
- for _, root := range certs { |
|
264 |
- roots.AddCert(root) |
|
265 |
- } |
|
266 |
- |
|
267 |
- return roots, nil |
|
268 |
-} |
|
269 |
- |
|
270 |
-// GetAPIServerCertCAPool returns the cert pool containing the roots for the API server cert |
|
271 |
-func (cfg Config) GetAPIServerCertCAPool() (*x509.CertPool, error) { |
|
272 |
- ca, err := cfg.newCA() |
|
273 |
- if err != nil { |
|
274 |
- return nil, err |
|
275 |
- } |
|
276 |
- roots := x509.NewCertPool() |
|
277 |
- for _, root := range ca.Config.Roots { |
|
278 |
- roots.AddCert(root) |
|
279 |
- } |
|
280 |
- return roots, nil |
|
281 |
-} |
|
282 |
- |
|
283 |
-func (cfg Config) getOAuthClientCertCAs() ([]*x509.Certificate, error) { |
|
284 |
- caFile := GetOAuthRequestHeaderCAFile() |
|
285 |
- if len(caFile) == 0 { |
|
286 |
- return nil, nil |
|
287 |
- } |
|
288 |
- caPEMBlock, err := ioutil.ReadFile(caFile) |
|
289 |
- if err != nil { |
|
290 |
- return nil, err |
|
291 |
- } |
|
292 |
- certs, err := crypto.CertsFromPEM(caPEMBlock) |
|
293 |
- if err != nil { |
|
294 |
- return nil, fmt.Errorf("Error reading %s: %s", caFile, err) |
|
295 |
- } |
|
296 |
- return certs, nil |
|
297 |
-} |
|
298 |
- |
|
299 |
-func (cfg Config) getAPIClientCertCAs() ([]*x509.Certificate, error) { |
|
300 |
- ca, err := cfg.newCA() |
|
301 |
- if err != nil { |
|
302 |
- return nil, err |
|
303 |
- } |
|
304 |
- return ca.Config.Roots, nil |
|
305 |
-} |
|
306 |
- |
|
307 |
-func (cfg Config) GetServerCertHostnames() ([]string, error) { |
|
308 |
- masterAddr, err := cfg.GetMasterAddress() |
|
309 |
- if err != nil { |
|
310 |
- return nil, err |
|
311 |
- } |
|
312 |
- masterPublicAddr, err := cfg.GetMasterPublicAddress() |
|
313 |
- if err != nil { |
|
314 |
- return nil, err |
|
315 |
- } |
|
316 |
- kubePublicAddr, err := cfg.GetKubernetesPublicAddress() |
|
317 |
- if err != nil { |
|
318 |
- return nil, err |
|
319 |
- } |
|
320 |
- assetPublicAddr, err := cfg.GetAssetPublicAddress() |
|
321 |
- if err != nil { |
|
322 |
- return nil, err |
|
323 |
- } |
|
324 |
- |
|
325 |
- // 172.17.42.1 enables the router to call back out to the master |
|
326 |
- // TODO: Remove 172.17.42.1 once we can figure out how to validate the master's cert from inside a pod, or tell pods the real IP for the master |
|
327 |
- allHostnames := util.NewStringSet("localhost", "127.0.0.1", "172.17.42.1", masterAddr.Host, masterPublicAddr.Host, kubePublicAddr.Host, assetPublicAddr.Host) |
|
328 |
- certHostnames := util.StringSet{} |
|
329 |
- for hostname := range allHostnames { |
|
330 |
- if host, _, err := net.SplitHostPort(hostname); err == nil { |
|
331 |
- // add the hostname without the port |
|
332 |
- certHostnames.Insert(host) |
|
333 |
- } else { |
|
334 |
- // add the originally specified hostname |
|
335 |
- certHostnames.Insert(hostname) |
|
336 |
- } |
|
337 |
- } |
|
338 |
- |
|
339 |
- return certHostnames.List(), nil |
|
340 |
-} |
|
341 |
- |
|
342 |
-func (cfg Config) GetMasterCert() (certFile string, keyFile string, err error) { |
|
343 |
- ca, err := cfg.newCA() |
|
344 |
- if err != nil { |
|
345 |
- return "", "", err |
|
346 |
- } |
|
347 |
- |
|
348 |
- certHostnames, err := cfg.GetServerCertHostnames() |
|
349 |
- if err != nil { |
|
350 |
- return "", "", err |
|
351 |
- } |
|
352 |
- |
|
353 |
- serverCert, err := ca.MakeServerCert("master", certHostnames) |
|
354 |
- if err != nil { |
|
355 |
- return "", "", err |
|
356 |
- } |
|
357 |
- |
|
358 |
- return serverCert.CertFile, serverCert.KeyFile, nil |
|
359 |
-} |
|
360 |
- |
|
361 |
-func (cfg Config) GetAssetCert() (certFile string, keyFile string, err error) { |
|
362 |
- ca, err := cfg.newCA() |
|
363 |
- if err != nil { |
|
364 |
- return "", "", err |
|
365 |
- } |
|
366 |
- |
|
367 |
- certHostnames, err := cfg.GetServerCertHostnames() |
|
368 |
- if err != nil { |
|
369 |
- return "", "", err |
|
370 |
- } |
|
371 |
- |
|
372 |
- serverCert, err := ca.MakeServerCert("master", certHostnames) |
|
373 |
- if err != nil { |
|
374 |
- return "", "", err |
|
375 |
- } |
|
376 |
- |
|
377 |
- return serverCert.CertFile, serverCert.KeyFile, nil |
|
378 |
-} |
|
379 |
- |
|
380 |
-func (cfg Config) newClientConfigTemplate() (*clientcmdapi.Config, error) { |
|
381 |
- masterAddr, err := cfg.GetMasterAddress() |
|
382 |
- if err != nil { |
|
383 |
- return nil, err |
|
384 |
- } |
|
385 |
- masterPublicAddr, err := cfg.GetMasterPublicAddress() |
|
386 |
- if err != nil { |
|
387 |
- return nil, err |
|
388 |
- } |
|
389 |
- |
|
390 |
- return &clientcmdapi.Config{ |
|
391 |
- Clusters: map[string]clientcmdapi.Cluster{ |
|
392 |
- "master": {Server: masterAddr.String()}, |
|
393 |
- "public-master": {Server: masterPublicAddr.String()}, |
|
394 |
- }, |
|
395 |
- Contexts: map[string]clientcmdapi.Context{ |
|
396 |
- "master": {Cluster: "master"}, |
|
397 |
- "public-master": {Cluster: "public-master"}, |
|
398 |
- }, |
|
399 |
- CurrentContext: "master", |
|
400 |
- }, nil |
|
401 |
-} |
|
402 |
- |
|
403 |
-func (cfg Config) GetKubeClient() (*kclient.Client, *kclient.Config, error) { |
|
404 |
- var err error |
|
405 |
- var kubeClientConfig *kclient.Config |
|
406 |
- |
|
407 |
- // if we're starting an all in one, make credentials for a kube client. |
|
408 |
- if cfg.StartKube { |
|
409 |
- kubeClientConfig, err = cfg.MintSystemClientCert("kube-client") |
|
410 |
- if err != nil { |
|
411 |
- return nil, nil, err |
|
412 |
- } |
|
413 |
- |
|
414 |
- } else { |
|
415 |
- // Get the kubernetes address we're using |
|
416 |
- kubeAddr, err := cfg.GetKubernetesAddress() |
|
417 |
- if err != nil { |
|
418 |
- return nil, nil, err |
|
419 |
- } |
|
420 |
- |
|
421 |
- // Try to get the kubeconfig |
|
422 |
- kubeCfg, ok, err := cfg.GetExternalKubernetesClientConfig() |
|
423 |
- if err != nil { |
|
424 |
- return nil, nil, err |
|
425 |
- } |
|
426 |
- if !ok { |
|
427 |
- // No kubeconfig was provided, so just make one that points at the specified host |
|
428 |
- // It probably won't work (since it has no auth), but they'll get to see failures logged |
|
429 |
- kubeCfg = &kclient.Config{Host: kubeAddr.String()} |
|
430 |
- } |
|
431 |
- |
|
432 |
- // Ensure the kubernetes address matches the one in the config |
|
433 |
- if kubeAddr.String() != kubeCfg.Host { |
|
434 |
- return nil, nil, fmt.Errorf("The Kubernetes server (%s) must match the server in the provided kubeconfig (%s)", kubeAddr.String(), kubeCfg.Host) |
|
435 |
- } |
|
436 |
- |
|
437 |
- kubeClientConfig = kubeCfg |
|
438 |
- } |
|
439 |
- |
|
440 |
- kubeClient, err := kclient.New(kubeClientConfig) |
|
441 |
- if err != nil { |
|
442 |
- return nil, nil, err |
|
443 |
- } |
|
444 |
- |
|
445 |
- return kubeClient, kubeClientConfig, nil |
|
446 |
-} |
|
447 |
- |
|
448 |
-func (cfg Config) GetOpenshiftClient() (*osclient.Client, *kclient.Config, error) { |
|
449 |
- clientConfig, err := cfg.MintSystemClientCert("openshift-client") |
|
450 |
- if err != nil { |
|
451 |
- return nil, nil, err |
|
452 |
- } |
|
453 |
- |
|
454 |
- client, err := osclient.New(clientConfig) |
|
455 |
- if err != nil { |
|
456 |
- return nil, nil, err |
|
457 |
- } |
|
458 |
- |
|
459 |
- return client, clientConfig, nil |
|
460 |
-} |
|
461 |
- |
|
462 |
-func (cfg Config) GetOpenshiftDeployerClientConfig() (*kclient.Config, error) { |
|
463 |
- clientConfig, err := cfg.MintSystemClientCert("openshift-deployer", "system:deployers") |
|
464 |
- if err != nil { |
|
465 |
- return nil, err |
|
466 |
- } |
|
467 |
- |
|
468 |
- return clientConfig, nil |
|
469 |
-} |
|
470 |
- |
|
471 |
-// known certs: |
|
472 |
-// openshiftClientUser := &user.DefaultInfo{Name: "system:openshift-client"} |
|
473 |
-// openshiftDeployerUser := &user.DefaultInfo{Name: "system:openshift-deployer", Groups: []string{"system:deployers"}} |
|
474 |
-// adminUser := &user.DefaultInfo{Name: "system:admin", Groups: []string{"system:cluster-admins"}} |
|
475 |
-// kubeClientUser := &user.DefaultInfo{Name: "system:kube-client"} |
|
476 |
-// // One for each node in cfg.GetNodeList() |
|
477 |
-func (cfg Config) MintSystemClientCert(username string, groups ...string) (*kclient.Config, error) { |
|
478 |
- ca, err := cfg.newCA() |
|
479 |
- if err != nil { |
|
480 |
- return nil, err |
|
481 |
- } |
|
482 |
- clientConfigTemplate, err := cfg.newClientConfigTemplate() |
|
483 |
- if err != nil { |
|
484 |
- return nil, err |
|
485 |
- } |
|
486 |
- |
|
487 |
- qualifiedUsername := "system:" + username |
|
488 |
- user := &user.DefaultInfo{Name: qualifiedUsername, Groups: groups} |
|
489 |
- config, err := ca.MakeClientConfig(username, user, *clientConfigTemplate) |
|
490 |
- if err != nil { |
|
491 |
- return nil, err |
|
492 |
- } |
|
493 |
- |
|
494 |
- return &config, nil |
|
495 |
-} |
|
496 |
- |
|
497 |
-func (cfg Config) MintNodeCerts() error { |
|
498 |
- for _, node := range cfg.NodeList { |
|
499 |
- username := "node-" + node |
|
500 |
- if _, err := cfg.MintSystemClientCert(username, "system:nodes"); err != nil { |
|
501 |
- return err |
|
502 |
- } |
|
503 |
- } |
|
504 |
- |
|
505 |
- return nil |
|
506 |
-} |
507 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,229 +0,0 @@ |
1 |
-package server |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "net" |
|
6 |
- "net/http" |
|
7 |
- "net/url" |
|
8 |
- "os" |
|
9 |
- "strconv" |
|
10 |
- "strings" |
|
11 |
- |
|
12 |
- kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
13 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities" |
|
14 |
- "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" |
|
15 |
- "github.com/coreos/go-systemd/daemon" |
|
16 |
- "github.com/golang/glog" |
|
17 |
- "github.com/openshift/origin/pkg/cmd/server/etcd" |
|
18 |
- "github.com/openshift/origin/pkg/cmd/server/kubernetes" |
|
19 |
- "github.com/openshift/origin/pkg/cmd/server/origin" |
|
20 |
-) |
|
21 |
- |
|
22 |
-func (cfg Config) startMaster() error { |
|
23 |
- // Allow privileged containers |
|
24 |
- // TODO: make this configurable and not the default https://github.com/openshift/origin/issues/662 |
|
25 |
- capabilities.Initialize(capabilities.Capabilities{ |
|
26 |
- AllowPrivileged: true, |
|
27 |
- }) |
|
28 |
- |
|
29 |
- cfg.MintNodeCerts() |
|
30 |
- cfg.MintSystemClientCert("admin", "system:cluster-admins") |
|
31 |
- cfg.MintSystemClientCert("openshift-deployer", "system:deployers") |
|
32 |
- cfg.MintSystemClientCert("openshift-client") |
|
33 |
- if cfg.StartKube { |
|
34 |
- cfg.MintSystemClientCert("kube-client") |
|
35 |
- } |
|
36 |
- glog.Infof("Client certificates and .kubeconfig files generated in %v", cfg.CertDir) |
|
37 |
- |
|
38 |
- openshiftConfig, err := cfg.BuildOriginMasterConfig() |
|
39 |
- if err != nil { |
|
40 |
- return err |
|
41 |
- } |
|
42 |
- |
|
43 |
- // must start policy caching immediately |
|
44 |
- openshiftConfig.RunPolicyCache() |
|
45 |
- |
|
46 |
- authConfig, err := cfg.BuildAuthConfig() |
|
47 |
- if err != nil { |
|
48 |
- return err |
|
49 |
- } |
|
50 |
- |
|
51 |
- glog.Infof("Nodes: %v", cfg.NodeList) |
|
52 |
- |
|
53 |
- if strings.Contains(openshiftConfig.MasterAddr, "127.0.0.1") { |
|
54 |
- glog.Infof("WARNING: Your server is being advertised only to the host - containers will not be able to communicate with the master without a proxy") |
|
55 |
- } |
|
56 |
- |
|
57 |
- if cfg.StartKube { |
|
58 |
- kubeConfig, err := cfg.BuildKubernetesMasterConfig(openshiftConfig.RequestContextMapper, openshiftConfig.KubeClient()) |
|
59 |
- if err != nil { |
|
60 |
- return err |
|
61 |
- } |
|
62 |
- kubeConfig.EnsurePortalFlags() |
|
63 |
- |
|
64 |
- openshiftConfig.Run([]origin.APIInstaller{kubeConfig}, []origin.APIInstaller{authConfig}) |
|
65 |
- |
|
66 |
- kubeConfig.RunScheduler() |
|
67 |
- kubeConfig.RunReplicationController() |
|
68 |
- kubeConfig.RunEndpointController() |
|
69 |
- kubeConfig.RunMinionController() |
|
70 |
- kubeConfig.RunResourceQuotaManager() |
|
71 |
- |
|
72 |
- } else { |
|
73 |
- kubeAddr, err := cfg.GetKubernetesAddress() |
|
74 |
- if err != nil { |
|
75 |
- return err |
|
76 |
- } |
|
77 |
- proxy := &kubernetes.ProxyConfig{ |
|
78 |
- KubernetesAddr: kubeAddr, |
|
79 |
- ClientConfig: &openshiftConfig.KubeClientConfig, |
|
80 |
- } |
|
81 |
- |
|
82 |
- openshiftConfig.Run([]origin.APIInstaller{proxy}, []origin.APIInstaller{authConfig}) |
|
83 |
- } |
|
84 |
- |
|
85 |
- // TODO: recording should occur in individual components |
|
86 |
- record.StartRecording(openshiftConfig.KubeClient().Events(""), kapi.EventSource{Component: "master"}) |
|
87 |
- |
|
88 |
- glog.Infof("Using images from %q", openshiftConfig.ImageFor("<component>")) |
|
89 |
- |
|
90 |
- openshiftConfig.RunDNSServer() |
|
91 |
- openshiftConfig.RunAssetServer() |
|
92 |
- openshiftConfig.RunBuildController() |
|
93 |
- openshiftConfig.RunBuildPodController() |
|
94 |
- openshiftConfig.RunBuildImageChangeTriggerController() |
|
95 |
- openshiftConfig.RunDeploymentController() |
|
96 |
- openshiftConfig.RunDeployerPodController() |
|
97 |
- openshiftConfig.RunDeploymentConfigController() |
|
98 |
- openshiftConfig.RunDeploymentConfigChangeController() |
|
99 |
- openshiftConfig.RunDeploymentImageChangeTriggerController() |
|
100 |
- openshiftConfig.RunProjectAuthorizationCache() |
|
101 |
- |
|
102 |
- return nil |
|
103 |
-} |
|
104 |
- |
|
105 |
-// run launches the appropriate startup modes or returns an error. |
|
106 |
-func (cfg Config) Start(args []string) error { |
|
107 |
- if cfg.WriteConfigOnly { |
|
108 |
- return nil |
|
109 |
- } |
|
110 |
- |
|
111 |
- switch { |
|
112 |
- case cfg.StartMaster && cfg.StartNode: |
|
113 |
- glog.Infof("Starting an OpenShift all-in-one, reachable at %s (etcd: %s)", cfg.MasterAddr.String(), cfg.EtcdAddr.String()) |
|
114 |
- if cfg.MasterPublicAddr.Provided { |
|
115 |
- glog.Infof("OpenShift master public address is %s", cfg.MasterPublicAddr.String()) |
|
116 |
- } |
|
117 |
- |
|
118 |
- case cfg.StartMaster: |
|
119 |
- glog.Infof("Starting an OpenShift master, reachable at %s (etcd: %s)", cfg.MasterAddr.String(), cfg.EtcdAddr.String()) |
|
120 |
- if cfg.MasterPublicAddr.Provided { |
|
121 |
- glog.Infof("OpenShift master public address is %s", cfg.MasterPublicAddr.String()) |
|
122 |
- } |
|
123 |
- |
|
124 |
- case cfg.StartNode: |
|
125 |
- glog.Infof("Starting an OpenShift node, connecting to %s", cfg.MasterAddr.String()) |
|
126 |
- |
|
127 |
- } |
|
128 |
- |
|
129 |
- if cfg.StartEtcd { |
|
130 |
- if err := cfg.RunEtcd(); err != nil { |
|
131 |
- return err |
|
132 |
- } |
|
133 |
- } |
|
134 |
- |
|
135 |
- if env("OPENSHIFT_PROFILE", "") == "web" { |
|
136 |
- go func() { |
|
137 |
- glog.Infof("Starting profiling endpoint at http://127.0.0.1:6060/debug/pprof/") |
|
138 |
- glog.Fatal(http.ListenAndServe("127.0.0.1:6060", nil)) |
|
139 |
- }() |
|
140 |
- } |
|
141 |
- |
|
142 |
- if cfg.StartMaster { |
|
143 |
- if err := cfg.startMaster(); err != nil { |
|
144 |
- return err |
|
145 |
- } |
|
146 |
- } |
|
147 |
- |
|
148 |
- if cfg.StartNode { |
|
149 |
- kubeClient, _, err := cfg.GetKubeClient() |
|
150 |
- if err != nil { |
|
151 |
- return err |
|
152 |
- } |
|
153 |
- |
|
154 |
- if !cfg.StartMaster { |
|
155 |
- // TODO: recording should occur in individual components |
|
156 |
- record.StartRecording(kubeClient.Events(""), kapi.EventSource{Component: "node"}) |
|
157 |
- } |
|
158 |
- |
|
159 |
- nodeConfig, err := cfg.BuildKubernetesNodeConfig() |
|
160 |
- if err != nil { |
|
161 |
- return err |
|
162 |
- } |
|
163 |
- |
|
164 |
- nodeConfig.EnsureVolumeDir() |
|
165 |
- nodeConfig.EnsureDocker(cfg.Docker) |
|
166 |
- nodeConfig.RunProxy() |
|
167 |
- nodeConfig.RunKubelet() |
|
168 |
- } |
|
169 |
- |
|
170 |
- daemon.SdNotify("READY=1") |
|
171 |
- select {} |
|
172 |
- |
|
173 |
- return nil |
|
174 |
-} |
|
175 |
- |
|
176 |
-func envInt(key string, defaultValue int32, minValue int32) int32 { |
|
177 |
- value, err := strconv.ParseInt(env(key, fmt.Sprintf("%d", defaultValue)), 10, 32) |
|
178 |
- if err != nil || int32(value) < minValue { |
|
179 |
- glog.Warningf("Invalid %s. Defaulting to %d.", key, defaultValue) |
|
180 |
- return defaultValue |
|
181 |
- } |
|
182 |
- return int32(value) |
|
183 |
-} |
|
184 |
- |
|
185 |
-// env returns an environment variable or a default value if not specified. |
|
186 |
-func env(key string, defaultValue string) string { |
|
187 |
- val := os.Getenv(key) |
|
188 |
- if len(val) == 0 { |
|
189 |
- return defaultValue |
|
190 |
- } |
|
191 |
- return val |
|
192 |
-} |
|
193 |
- |
|
194 |
-func (cfg Config) RunEtcd() error { |
|
195 |
- etcdAddr, err := cfg.GetEtcdAddress() |
|
196 |
- if err != nil { |
|
197 |
- return err |
|
198 |
- } |
|
199 |
- |
|
200 |
- etcdConfig := &etcd.Config{ |
|
201 |
- BindAddr: cfg.GetEtcdBindAddress(), |
|
202 |
- PeerBindAddr: cfg.GetEtcdPeerBindAddress(), |
|
203 |
- MasterAddr: etcdAddr.Host, |
|
204 |
- EtcdDir: cfg.EtcdDir, |
|
205 |
- } |
|
206 |
- |
|
207 |
- etcdConfig.Run() |
|
208 |
- |
|
209 |
- return nil |
|
210 |
-} |
|
211 |
- |
|
212 |
-func getHost(theURL url.URL) string { |
|
213 |
- host, _, err := net.SplitHostPort(theURL.Host) |
|
214 |
- if err != nil { |
|
215 |
- return theURL.Host |
|
216 |
- } |
|
217 |
- |
|
218 |
- return host |
|
219 |
-} |
|
220 |
- |
|
221 |
-func getPort(theURL url.URL) int { |
|
222 |
- _, port, err := net.SplitHostPort(theURL.Host) |
|
223 |
- if err != nil { |
|
224 |
- return 0 |
|
225 |
- } |
|
226 |
- |
|
227 |
- intport, _ := strconv.Atoi(port) |
|
228 |
- return intport |
|
229 |
-} |
230 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,24 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/spf13/pflag" |
|
4 |
+ |
|
5 |
+ "github.com/openshift/origin/pkg/cmd/flagtypes" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+// BindAddrArg is a struct that the command stores flag values into. |
|
9 |
+type BindAddrArg struct { |
|
10 |
+ BindAddr flagtypes.Addr |
|
11 |
+} |
|
12 |
+ |
|
13 |
+func BindBindAddrArg(args *BindAddrArg, flags *pflag.FlagSet, prefix string) { |
|
14 |
+ flags.Var(&args.BindAddr, prefix+"listen", "The address to listen for connections on (host, host:port, or URL).") |
|
15 |
+} |
|
16 |
+ |
|
17 |
+func NewDefaultBindAddrArg() *BindAddrArg { |
|
18 |
+ config := &BindAddrArg{ |
|
19 |
+ BindAddr: flagtypes.Addr{Value: "0.0.0.0:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
20 |
+ } |
|
21 |
+ |
|
22 |
+ return config |
|
23 |
+} |
0 | 24 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,20 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/spf13/pflag" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+type CertArgs struct { |
|
7 |
+ CertDir string |
|
8 |
+ CreateCerts bool |
|
9 |
+ OverwriteCerts bool |
|
10 |
+} |
|
11 |
+ |
|
12 |
+func BindCertArgs(args *CertArgs, flags *pflag.FlagSet, prefix string) { |
|
13 |
+ flags.BoolVar(&args.CreateCerts, prefix+"create-certs", true, "Create any missing certificates required for launch or for writing the config file.") |
|
14 |
+ flags.StringVar(&args.CertDir, prefix+"cert-dir", "openshift.local.certificates", "The certificate data directory.") |
|
15 |
+} |
|
16 |
+ |
|
17 |
+func NewDefaultCertArgs() *CertArgs { |
|
18 |
+ return &CertArgs{CreateCerts: true} |
|
19 |
+} |
0 | 20 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,338 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "io/ioutil" |
|
4 |
+ "os" |
|
5 |
+ "strconv" |
|
6 |
+ "strings" |
|
7 |
+ "testing" |
|
8 |
+ |
|
9 |
+ "github.com/spf13/cobra" |
|
10 |
+ |
|
11 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+func TestCommandBindingListen(t *testing.T) { |
|
15 |
+ valueToSet := "http://example.org:9123" |
|
16 |
+ actualCfg := executeMasterCommand([]string{"--listen=" + valueToSet}) |
|
17 |
+ |
|
18 |
+ expectedArgs := NewDefaultMasterArgs() |
|
19 |
+ expectedArgs.BindAddrArg.BindAddr.Set(valueToSet) |
|
20 |
+ |
|
21 |
+ if expectedArgs.BindAddrArg.BindAddr.String() != actualCfg.BindAddrArg.BindAddr.String() { |
|
22 |
+ t.Errorf("expected %v, got %v", expectedArgs.BindAddrArg.BindAddr.String(), actualCfg.BindAddrArg.BindAddr.String()) |
|
23 |
+ } |
|
24 |
+} |
|
25 |
+ |
|
26 |
+func TestCommandBindingMaster(t *testing.T) { |
|
27 |
+ valueToSet := "http://example.org:9123" |
|
28 |
+ actualCfg := executeMasterCommand([]string{"--master=" + valueToSet}) |
|
29 |
+ |
|
30 |
+ expectedArgs := NewDefaultMasterArgs() |
|
31 |
+ expectedArgs.MasterAddr.Set(valueToSet) |
|
32 |
+ |
|
33 |
+ if expectedArgs.MasterAddr.String() != actualCfg.MasterAddr.String() { |
|
34 |
+ t.Errorf("expected %v, got %v", expectedArgs.MasterAddr.String(), actualCfg.MasterAddr.String()) |
|
35 |
+ } |
|
36 |
+} |
|
37 |
+ |
|
38 |
+func TestCommandBindingMasterPublic(t *testing.T) { |
|
39 |
+ valueToSet := "http://example.org:9123" |
|
40 |
+ actualCfg := executeMasterCommand([]string{"--public-master=" + valueToSet}) |
|
41 |
+ |
|
42 |
+ expectedArgs := NewDefaultMasterArgs() |
|
43 |
+ expectedArgs.MasterPublicAddr.Set(valueToSet) |
|
44 |
+ |
|
45 |
+ if expectedArgs.MasterPublicAddr.String() != actualCfg.MasterPublicAddr.String() { |
|
46 |
+ t.Errorf("expected %v, got %v", expectedArgs.MasterPublicAddr.String(), actualCfg.MasterPublicAddr.String()) |
|
47 |
+ } |
|
48 |
+} |
|
49 |
+ |
|
50 |
+func TestCommandBindingEtcd(t *testing.T) { |
|
51 |
+ valueToSet := "http://example.org:9123" |
|
52 |
+ actualCfg := executeMasterCommand([]string{"--etcd=" + valueToSet}) |
|
53 |
+ |
|
54 |
+ expectedArgs := NewDefaultMasterArgs() |
|
55 |
+ expectedArgs.EtcdAddr.Set(valueToSet) |
|
56 |
+ |
|
57 |
+ if expectedArgs.EtcdAddr.String() != actualCfg.EtcdAddr.String() { |
|
58 |
+ t.Errorf("expected %v, got %v", expectedArgs.EtcdAddr.String(), actualCfg.EtcdAddr.String()) |
|
59 |
+ } |
|
60 |
+} |
|
61 |
+ |
|
62 |
+func TestCommandBindingKubernetes(t *testing.T) { |
|
63 |
+ valueToSet := "http://example.org:9123" |
|
64 |
+ actualCfg := executeMasterCommand([]string{"--kubernetes=" + valueToSet}) |
|
65 |
+ |
|
66 |
+ expectedArgs := NewDefaultMasterArgs() |
|
67 |
+ expectedArgs.KubeConnectionArgs.KubernetesAddr.Set(valueToSet) |
|
68 |
+ |
|
69 |
+ if expectedArgs.KubeConnectionArgs.KubernetesAddr.String() != actualCfg.KubeConnectionArgs.KubernetesAddr.String() { |
|
70 |
+ t.Errorf("expected %v, got %v", expectedArgs.KubeConnectionArgs.KubernetesAddr.String(), actualCfg.KubeConnectionArgs.KubernetesAddr.String()) |
|
71 |
+ } |
|
72 |
+} |
|
73 |
+ |
|
74 |
+func TestCommandBindingKubernetesPublic(t *testing.T) { |
|
75 |
+ valueToSet := "http://example.org:9123" |
|
76 |
+ actualCfg := executeMasterCommand([]string{"--public-kubernetes=" + valueToSet}) |
|
77 |
+ |
|
78 |
+ expectedArgs := NewDefaultMasterArgs() |
|
79 |
+ expectedArgs.KubernetesPublicAddr.Set(valueToSet) |
|
80 |
+ |
|
81 |
+ if expectedArgs.KubernetesPublicAddr.String() != actualCfg.KubernetesPublicAddr.String() { |
|
82 |
+ t.Errorf("expected %v, got %v", expectedArgs.KubernetesPublicAddr.String(), actualCfg.KubernetesPublicAddr.String()) |
|
83 |
+ } |
|
84 |
+} |
|
85 |
+ |
|
86 |
+func TestCommandBindingPortalNet(t *testing.T) { |
|
87 |
+ valueToSet := "192.168.0.0/16" |
|
88 |
+ actualCfg := executeMasterCommand([]string{"--portal-net=" + valueToSet}) |
|
89 |
+ |
|
90 |
+ expectedArgs := NewDefaultMasterArgs() |
|
91 |
+ expectedArgs.PortalNet.Set(valueToSet) |
|
92 |
+ |
|
93 |
+ if expectedArgs.PortalNet.String() != actualCfg.PortalNet.String() { |
|
94 |
+ t.Errorf("expected %v, got %v", expectedArgs.PortalNet.String(), actualCfg.PortalNet.String()) |
|
95 |
+ } |
|
96 |
+} |
|
97 |
+ |
|
98 |
+func TestCommandBindingImageTemplateFormat(t *testing.T) { |
|
99 |
+ valueToSet := "some-format-string" |
|
100 |
+ actualCfg := executeMasterCommand([]string{"--images=" + valueToSet}) |
|
101 |
+ |
|
102 |
+ expectedArgs := NewDefaultMasterArgs() |
|
103 |
+ expectedArgs.ImageFormatArgs.ImageTemplate.Format = valueToSet |
|
104 |
+ |
|
105 |
+ if expectedArgs.ImageFormatArgs.ImageTemplate.Format != actualCfg.ImageFormatArgs.ImageTemplate.Format { |
|
106 |
+ t.Errorf("expected %v, got %v", expectedArgs.ImageFormatArgs.ImageTemplate.Format, actualCfg.ImageFormatArgs.ImageTemplate.Format) |
|
107 |
+ } |
|
108 |
+} |
|
109 |
+ |
|
110 |
+func TestCommandBindingImageLatest(t *testing.T) { |
|
111 |
+ expectedArgs := NewDefaultMasterArgs() |
|
112 |
+ |
|
113 |
+ valueToSet := strconv.FormatBool(!expectedArgs.ImageFormatArgs.ImageTemplate.Latest) |
|
114 |
+ actualCfg := executeMasterCommand([]string{"--latest-images=" + valueToSet}) |
|
115 |
+ |
|
116 |
+ expectedArgs.ImageFormatArgs.ImageTemplate.Latest = !expectedArgs.ImageFormatArgs.ImageTemplate.Latest |
|
117 |
+ |
|
118 |
+ if expectedArgs.ImageFormatArgs.ImageTemplate.Latest != actualCfg.ImageFormatArgs.ImageTemplate.Latest { |
|
119 |
+ t.Errorf("expected %v, got %v", expectedArgs.ImageFormatArgs.ImageTemplate.Latest, actualCfg.ImageFormatArgs.ImageTemplate.Latest) |
|
120 |
+ } |
|
121 |
+} |
|
122 |
+ |
|
123 |
+func TestCommandBindingVolumeDir(t *testing.T) { |
|
124 |
+ valueToSet := "some-string" |
|
125 |
+ actualCfg := executeNodeCommand([]string{"--volume-dir=" + valueToSet}) |
|
126 |
+ |
|
127 |
+ expectedArgs := NewDefaultNodeArgs() |
|
128 |
+ expectedArgs.VolumeDir = valueToSet |
|
129 |
+ |
|
130 |
+ if expectedArgs.VolumeDir != actualCfg.VolumeDir { |
|
131 |
+ t.Errorf("expected %v, got %v", expectedArgs.VolumeDir, actualCfg.VolumeDir) |
|
132 |
+ } |
|
133 |
+} |
|
134 |
+ |
|
135 |
+func TestCommandBindingEtcdDir(t *testing.T) { |
|
136 |
+ valueToSet := "some-string" |
|
137 |
+ actualCfg := executeMasterCommand([]string{"--etcd-dir=" + valueToSet}) |
|
138 |
+ |
|
139 |
+ expectedArgs := NewDefaultMasterArgs() |
|
140 |
+ expectedArgs.EtcdDir = valueToSet |
|
141 |
+ |
|
142 |
+ if expectedArgs.EtcdDir != actualCfg.EtcdDir { |
|
143 |
+ t.Errorf("expected %v, got %v", expectedArgs.EtcdDir, actualCfg.EtcdDir) |
|
144 |
+ } |
|
145 |
+} |
|
146 |
+ |
|
147 |
+func TestCommandBindingCertDir(t *testing.T) { |
|
148 |
+ valueToSet := "some-string" |
|
149 |
+ actualCfg := executeMasterCommand([]string{"--cert-dir=" + valueToSet}) |
|
150 |
+ |
|
151 |
+ expectedArgs := NewDefaultMasterArgs() |
|
152 |
+ expectedArgs.CertArgs.CertDir = valueToSet |
|
153 |
+ |
|
154 |
+ if expectedArgs.CertArgs.CertDir != actualCfg.CertArgs.CertDir { |
|
155 |
+ t.Errorf("expected %v, got %v", expectedArgs.CertArgs.CertDir, actualCfg.CertArgs.CertDir) |
|
156 |
+ } |
|
157 |
+} |
|
158 |
+ |
|
159 |
+func TestCommandBindingHostname(t *testing.T) { |
|
160 |
+ valueToSet := "some-string" |
|
161 |
+ actualCfg := executeNodeCommand([]string{"--hostname=" + valueToSet}) |
|
162 |
+ |
|
163 |
+ expectedArgs := NewDefaultNodeArgs() |
|
164 |
+ expectedArgs.NodeName = valueToSet |
|
165 |
+ |
|
166 |
+ if expectedArgs.NodeName != actualCfg.NodeName { |
|
167 |
+ t.Errorf("expected %v, got %v", expectedArgs.NodeName, actualCfg.NodeName) |
|
168 |
+ } |
|
169 |
+} |
|
170 |
+ |
|
171 |
+// AllInOne always adds the default hostname |
|
172 |
+func TestCommandBindingNodesForAllInOneAppend(t *testing.T) { |
|
173 |
+ valueToSet := "first,second,third" |
|
174 |
+ actualMasterCfg, actualNodeConfig := executeAllInOneCommand([]string{"--nodes=" + valueToSet}) |
|
175 |
+ |
|
176 |
+ expectedArgs := NewDefaultMasterArgs() |
|
177 |
+ |
|
178 |
+ stringList := util.StringList{} |
|
179 |
+ stringList.Set(valueToSet + "," + strings.ToLower(actualNodeConfig.NodeName)) |
|
180 |
+ expectedArgs.NodeList.Set(strings.Join(util.NewStringSet(stringList...).List(), ",")) |
|
181 |
+ |
|
182 |
+ if expectedArgs.NodeList.String() != actualMasterCfg.NodeList.String() { |
|
183 |
+ t.Errorf("expected %v, got %v", expectedArgs.NodeList, actualMasterCfg.NodeList) |
|
184 |
+ } |
|
185 |
+} |
|
186 |
+ |
|
187 |
+// AllInOne always adds the default hostname |
|
188 |
+func TestCommandBindingNodesForAllInOneAppendNoDupes(t *testing.T) { |
|
189 |
+ valueToSet := "first,localhost,second,third" |
|
190 |
+ actualMasterCfg, _ := executeAllInOneCommand([]string{"--nodes=" + valueToSet, "--hostname=LOCALHOST"}) |
|
191 |
+ |
|
192 |
+ expectedArgs := NewDefaultMasterArgs() |
|
193 |
+ expectedArgs.NodeList.Set(valueToSet) |
|
194 |
+ |
|
195 |
+ util.NewStringSet() |
|
196 |
+ |
|
197 |
+ if expectedArgs.NodeList.String() != actualMasterCfg.NodeList.String() { |
|
198 |
+ t.Errorf("expected %v, got %v", expectedArgs.NodeList, actualMasterCfg.NodeList) |
|
199 |
+ } |
|
200 |
+} |
|
201 |
+ |
|
202 |
+// AllInOne always adds the default hostname |
|
203 |
+func TestCommandBindingNodesDefaultingAllInOne(t *testing.T) { |
|
204 |
+ actualMasterCfg, _ := executeAllInOneCommand([]string{}) |
|
205 |
+ |
|
206 |
+ expectedArgs := NewDefaultMasterArgs() |
|
207 |
+ expectedNodeArgs := NewDefaultNodeArgs() |
|
208 |
+ expectedArgs.NodeList.Set(strings.ToLower(expectedNodeArgs.NodeName)) |
|
209 |
+ |
|
210 |
+ if expectedArgs.NodeList.String() != actualMasterCfg.NodeList.String() { |
|
211 |
+ t.Errorf("expected %v, got %v", expectedArgs.NodeList, actualMasterCfg.NodeList) |
|
212 |
+ } |
|
213 |
+} |
|
214 |
+ |
|
215 |
+// explicit start master never modifies the NodeList |
|
216 |
+func TestCommandBindingNodesForMaster(t *testing.T) { |
|
217 |
+ valueToSet := "first,second,third" |
|
218 |
+ actualCfg := executeMasterCommand([]string{"master", "--nodes=" + valueToSet}) |
|
219 |
+ |
|
220 |
+ expectedArgs := NewDefaultMasterArgs() |
|
221 |
+ expectedArgs.NodeList.Set(valueToSet) |
|
222 |
+ |
|
223 |
+ if expectedArgs.NodeList.String() != actualCfg.NodeList.String() { |
|
224 |
+ t.Errorf("expected %v, got %v", expectedArgs.NodeList, actualCfg.NodeList) |
|
225 |
+ } |
|
226 |
+} |
|
227 |
+ |
|
228 |
+// explicit start master never modifies the NodeList |
|
229 |
+func TestCommandBindingNodesDefaultingMaster(t *testing.T) { |
|
230 |
+ actualCfg := executeMasterCommand([]string{"master"}) |
|
231 |
+ |
|
232 |
+ expectedArgs := NewDefaultMasterArgs() |
|
233 |
+ expectedArgs.NodeList.Set("") |
|
234 |
+ |
|
235 |
+ if expectedArgs.NodeList.String() != actualCfg.NodeList.String() { |
|
236 |
+ t.Errorf("expected %v, got %v", expectedArgs.NodeList, actualCfg.NodeList) |
|
237 |
+ } |
|
238 |
+} |
|
239 |
+ |
|
240 |
+func TestCommandBindingCors(t *testing.T) { |
|
241 |
+ valueToSet := "first,second,third" |
|
242 |
+ actualCfg := executeMasterCommand([]string{"--cors-allowed-origins=" + valueToSet}) |
|
243 |
+ |
|
244 |
+ expectedArgs := NewDefaultMasterArgs() |
|
245 |
+ expectedArgs.CORSAllowedOrigins.Set(valueToSet) |
|
246 |
+ |
|
247 |
+ if expectedArgs.CORSAllowedOrigins.String() != actualCfg.CORSAllowedOrigins.String() { |
|
248 |
+ t.Errorf("expected %v, got %v", expectedArgs.CORSAllowedOrigins, actualCfg.CORSAllowedOrigins) |
|
249 |
+ } |
|
250 |
+} |
|
251 |
+ |
|
252 |
+func executeMasterCommand(args []string) *MasterArgs { |
|
253 |
+ fakeConfigFile, _ := ioutil.TempFile("", "") |
|
254 |
+ defer os.Remove(fakeConfigFile.Name()) |
|
255 |
+ |
|
256 |
+ argsToUse := make([]string, 0, 4+len(args)) |
|
257 |
+ argsToUse = append(argsToUse, "master") |
|
258 |
+ argsToUse = append(argsToUse, args...) |
|
259 |
+ argsToUse = append(argsToUse, "--write-config") |
|
260 |
+ argsToUse = append(argsToUse, "--create-certs=false") |
|
261 |
+ argsToUse = append(argsToUse, "--config="+fakeConfigFile.Name()) |
|
262 |
+ |
|
263 |
+ root := &cobra.Command{ |
|
264 |
+ Use: "openshift", |
|
265 |
+ Short: "test", |
|
266 |
+ Long: "", |
|
267 |
+ Run: func(c *cobra.Command, args []string) { |
|
268 |
+ c.Help() |
|
269 |
+ }, |
|
270 |
+ } |
|
271 |
+ |
|
272 |
+ openshiftStartCommand, cfg := NewCommandStartMaster() |
|
273 |
+ root.AddCommand(openshiftStartCommand) |
|
274 |
+ root.SetArgs(argsToUse) |
|
275 |
+ root.Execute() |
|
276 |
+ |
|
277 |
+ return cfg.MasterArgs |
|
278 |
+} |
|
279 |
+ |
|
280 |
+func executeAllInOneCommand(args []string) (*MasterArgs, *NodeArgs) { |
|
281 |
+ fakeMasterConfigFile, _ := ioutil.TempFile("", "") |
|
282 |
+ defer os.Remove(fakeMasterConfigFile.Name()) |
|
283 |
+ fakeNodeConfigFile, _ := ioutil.TempFile("", "") |
|
284 |
+ defer os.Remove(fakeNodeConfigFile.Name()) |
|
285 |
+ |
|
286 |
+ argsToUse := make([]string, 0, 4+len(args)) |
|
287 |
+ argsToUse = append(argsToUse, "start") |
|
288 |
+ argsToUse = append(argsToUse, args...) |
|
289 |
+ argsToUse = append(argsToUse, "--write-config") |
|
290 |
+ argsToUse = append(argsToUse, "--create-certs=false") |
|
291 |
+ argsToUse = append(argsToUse, "--master-config="+fakeMasterConfigFile.Name()) |
|
292 |
+ argsToUse = append(argsToUse, "--node-config="+fakeNodeConfigFile.Name()) |
|
293 |
+ |
|
294 |
+ root := &cobra.Command{ |
|
295 |
+ Use: "openshift", |
|
296 |
+ Short: "test", |
|
297 |
+ Long: "", |
|
298 |
+ Run: func(c *cobra.Command, args []string) { |
|
299 |
+ c.Help() |
|
300 |
+ }, |
|
301 |
+ } |
|
302 |
+ |
|
303 |
+ openshiftStartCommand, cfg := NewCommandStartAllInOne() |
|
304 |
+ root.AddCommand(openshiftStartCommand) |
|
305 |
+ root.SetArgs(argsToUse) |
|
306 |
+ root.Execute() |
|
307 |
+ |
|
308 |
+ return cfg.MasterArgs, cfg.NodeArgs |
|
309 |
+} |
|
310 |
+ |
|
311 |
+func executeNodeCommand(args []string) *NodeArgs { |
|
312 |
+ fakeConfigFile, _ := ioutil.TempFile("", "") |
|
313 |
+ defer os.Remove(fakeConfigFile.Name()) |
|
314 |
+ |
|
315 |
+ argsToUse := make([]string, 0, 4+len(args)) |
|
316 |
+ argsToUse = append(argsToUse, "node") |
|
317 |
+ argsToUse = append(argsToUse, args...) |
|
318 |
+ argsToUse = append(argsToUse, "--write-config") |
|
319 |
+ argsToUse = append(argsToUse, "--create-certs=false") |
|
320 |
+ argsToUse = append(argsToUse, "--config="+fakeConfigFile.Name()) |
|
321 |
+ |
|
322 |
+ root := &cobra.Command{ |
|
323 |
+ Use: "openshift", |
|
324 |
+ Short: "test", |
|
325 |
+ Long: "", |
|
326 |
+ Run: func(c *cobra.Command, args []string) { |
|
327 |
+ c.Help() |
|
328 |
+ }, |
|
329 |
+ } |
|
330 |
+ |
|
331 |
+ openshiftStartCommand, cfg := NewCommandStartNode() |
|
332 |
+ root.AddCommand(openshiftStartCommand) |
|
333 |
+ root.SetArgs(argsToUse) |
|
334 |
+ root.Execute() |
|
335 |
+ |
|
336 |
+ return cfg.NodeArgs |
|
337 |
+} |
0 | 338 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,467 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "testing" |
|
4 |
+ |
|
5 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
6 |
+ clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" |
|
7 |
+ "github.com/openshift/origin/pkg/cmd/util" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+func TestMasterPublicAddressDefaulting(t *testing.T) { |
|
11 |
+ expected := "http://example.com:9012" |
|
12 |
+ |
|
13 |
+ masterArgs := NewDefaultMasterArgs() |
|
14 |
+ masterArgs.MasterAddr.Set(expected) |
|
15 |
+ |
|
16 |
+ actual, err := masterArgs.GetMasterPublicAddress() |
|
17 |
+ if err != nil { |
|
18 |
+ t.Errorf("unexpected error: %v", err) |
|
19 |
+ } |
|
20 |
+ if expected != actual.String() { |
|
21 |
+ t.Errorf("expected %v, got %v", expected, actual) |
|
22 |
+ } |
|
23 |
+} |
|
24 |
+ |
|
25 |
+func TestMasterPublicAddressExplicit(t *testing.T) { |
|
26 |
+ expected := "http://external.com:12445" |
|
27 |
+ |
|
28 |
+ masterArgs := NewDefaultMasterArgs() |
|
29 |
+ masterArgs.MasterAddr.Set("http://internal.com:9012") |
|
30 |
+ masterArgs.MasterPublicAddr.Set(expected) |
|
31 |
+ |
|
32 |
+ actual, err := masterArgs.GetMasterPublicAddress() |
|
33 |
+ if err != nil { |
|
34 |
+ t.Errorf("unexpected error: %v", err) |
|
35 |
+ } |
|
36 |
+ if expected != actual.String() { |
|
37 |
+ t.Errorf("expected %v, got %v", expected, actual) |
|
38 |
+ } |
|
39 |
+} |
|
40 |
+ |
|
41 |
+func TestAssetPublicAddressDefaulting(t *testing.T) { |
|
42 |
+ master := "http://example.com:9011" |
|
43 |
+ expected := "http://example.com:9012" |
|
44 |
+ |
|
45 |
+ masterArgs := NewDefaultMasterArgs() |
|
46 |
+ masterArgs.MasterAddr.Set(master) |
|
47 |
+ |
|
48 |
+ actual, err := masterArgs.GetAssetPublicAddress() |
|
49 |
+ if err != nil { |
|
50 |
+ t.Errorf("unexpected error: %v", err) |
|
51 |
+ } |
|
52 |
+ if expected != actual.String() { |
|
53 |
+ t.Errorf("expected %v, got %v", expected, actual) |
|
54 |
+ } |
|
55 |
+} |
|
56 |
+ |
|
57 |
+func TestAssetPublicAddressExplicit(t *testing.T) { |
|
58 |
+ master := "http://example.com:9011" |
|
59 |
+ expected := "https://example.com:9014" |
|
60 |
+ |
|
61 |
+ masterArgs := NewDefaultMasterArgs() |
|
62 |
+ masterArgs.MasterAddr.Set(master) |
|
63 |
+ masterArgs.AssetPublicAddr.Set(expected) |
|
64 |
+ |
|
65 |
+ actual, err := masterArgs.GetAssetPublicAddress() |
|
66 |
+ if err != nil { |
|
67 |
+ t.Errorf("unexpected error: %v", err) |
|
68 |
+ } |
|
69 |
+ if expected != actual.String() { |
|
70 |
+ t.Errorf("expected %v, got %v", expected, actual) |
|
71 |
+ } |
|
72 |
+} |
|
73 |
+ |
|
74 |
+func TestAssetBindAddressDefaulting(t *testing.T) { |
|
75 |
+ bind := "1.2.3.4:9011" |
|
76 |
+ expected := "1.2.3.4:9012" |
|
77 |
+ |
|
78 |
+ masterArgs := NewDefaultMasterArgs() |
|
79 |
+ masterArgs.BindAddrArg.BindAddr.Set(bind) |
|
80 |
+ |
|
81 |
+ actual := masterArgs.GetAssetBindAddress() |
|
82 |
+ if expected != actual { |
|
83 |
+ t.Errorf("expected %v, got %v", expected, actual) |
|
84 |
+ } |
|
85 |
+} |
|
86 |
+ |
|
87 |
+func TestAssetBindAddressExplicit(t *testing.T) { |
|
88 |
+ bind := "1.2.3.4:9011" |
|
89 |
+ expected := "2.3.4.5:1234" |
|
90 |
+ |
|
91 |
+ masterArgs := NewDefaultMasterArgs() |
|
92 |
+ masterArgs.BindAddrArg.BindAddr.Set(bind) |
|
93 |
+ masterArgs.AssetBindAddr.Set(expected) |
|
94 |
+ |
|
95 |
+ actual := masterArgs.GetAssetBindAddress() |
|
96 |
+ if expected != actual { |
|
97 |
+ t.Errorf("expected %v, got %v", expected, actual) |
|
98 |
+ } |
|
99 |
+} |
|
100 |
+ |
|
101 |
+func TestKubernetesPublicAddressDefaultToKubernetesAddress(t *testing.T) { |
|
102 |
+ expected := "http://example.com:9012" |
|
103 |
+ |
|
104 |
+ masterArgs := NewDefaultMasterArgs() |
|
105 |
+ masterArgs.KubeConnectionArgs.KubernetesAddr.Set(expected) |
|
106 |
+ masterArgs.MasterPublicAddr.Set("unexpectedpublicmaster") |
|
107 |
+ masterArgs.MasterAddr.Set("unexpectedmaster") |
|
108 |
+ |
|
109 |
+ actual, err := masterArgs.GetKubernetesPublicAddress() |
|
110 |
+ if err != nil { |
|
111 |
+ t.Fatalf("unexpected error: %v", err) |
|
112 |
+ } |
|
113 |
+ if expected != actual.String() { |
|
114 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
115 |
+ } |
|
116 |
+} |
|
117 |
+ |
|
118 |
+func TestKubernetesPublicAddressDefaultToPublicMasterAddress(t *testing.T) { |
|
119 |
+ expected := "http://example.com:9012" |
|
120 |
+ |
|
121 |
+ masterArgs := NewDefaultMasterArgs() |
|
122 |
+ masterArgs.MasterPublicAddr.Set(expected) |
|
123 |
+ masterArgs.MasterAddr.Set("unexpectedmaster") |
|
124 |
+ |
|
125 |
+ actual, err := masterArgs.GetKubernetesPublicAddress() |
|
126 |
+ if err != nil { |
|
127 |
+ t.Fatalf("unexpected error: %v", err) |
|
128 |
+ } |
|
129 |
+ if expected != actual.String() { |
|
130 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
131 |
+ } |
|
132 |
+} |
|
133 |
+ |
|
134 |
+func TestKubernetesPublicAddressDefaultToMasterAddress(t *testing.T) { |
|
135 |
+ expected := "http://example.com:9012" |
|
136 |
+ |
|
137 |
+ masterArgs := NewDefaultMasterArgs() |
|
138 |
+ masterArgs.MasterAddr.Set(expected) |
|
139 |
+ |
|
140 |
+ actual, err := masterArgs.GetKubernetesPublicAddress() |
|
141 |
+ if err != nil { |
|
142 |
+ t.Fatalf("unexpected error: %v", err) |
|
143 |
+ } |
|
144 |
+ if expected != actual.String() { |
|
145 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
146 |
+ } |
|
147 |
+} |
|
148 |
+ |
|
149 |
+func TestKubernetesPublicAddressExplicit(t *testing.T) { |
|
150 |
+ expected := "http://external.com:12445" |
|
151 |
+ |
|
152 |
+ masterArgs := NewDefaultMasterArgs() |
|
153 |
+ masterArgs.MasterAddr.Set("http://internal.com:9012") |
|
154 |
+ masterArgs.KubeConnectionArgs.KubernetesAddr.Set("http://internal.com:9013") |
|
155 |
+ masterArgs.MasterPublicAddr.Set("http://internal.com:9014") |
|
156 |
+ masterArgs.KubernetesPublicAddr.Set(expected) |
|
157 |
+ |
|
158 |
+ actual, err := masterArgs.GetKubernetesPublicAddress() |
|
159 |
+ if err != nil { |
|
160 |
+ t.Fatalf("unexpected error: %v", err) |
|
161 |
+ } |
|
162 |
+ if expected != actual.String() { |
|
163 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
164 |
+ } |
|
165 |
+} |
|
166 |
+ |
|
167 |
+func TestKubernetesAddressDefaulting(t *testing.T) { |
|
168 |
+ expected := "http://example.com:9012" |
|
169 |
+ |
|
170 |
+ masterArgs := NewDefaultMasterArgs() |
|
171 |
+ masterArgs.MasterAddr.Set(expected) |
|
172 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
173 |
+ |
|
174 |
+ actual, err := masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
175 |
+ if err != nil { |
|
176 |
+ t.Fatalf("unexpected error: %v", err) |
|
177 |
+ } |
|
178 |
+ if expected != actual.String() { |
|
179 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
180 |
+ } |
|
181 |
+} |
|
182 |
+ |
|
183 |
+func TestKubernetesAddressExplicit(t *testing.T) { |
|
184 |
+ expected := "http://external.com:12445" |
|
185 |
+ |
|
186 |
+ masterArgs := NewDefaultMasterArgs() |
|
187 |
+ masterArgs.MasterAddr.Set("http://internal.com:9012") |
|
188 |
+ masterArgs.KubeConnectionArgs.KubernetesAddr.Set(expected) |
|
189 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
190 |
+ |
|
191 |
+ actual, err := masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
192 |
+ if err != nil { |
|
193 |
+ t.Fatalf("unexpected error: %v", err) |
|
194 |
+ } |
|
195 |
+ if expected != actual.String() { |
|
196 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
197 |
+ } |
|
198 |
+} |
|
199 |
+ |
|
200 |
+func TestEtcdAddressDefaulting(t *testing.T) { |
|
201 |
+ expected := "http://example.com:4001" |
|
202 |
+ master := "https://example.com:9012" |
|
203 |
+ |
|
204 |
+ masterArgs := NewDefaultMasterArgs() |
|
205 |
+ masterArgs.MasterAddr.Set(master) |
|
206 |
+ |
|
207 |
+ actual, err := masterArgs.GetEtcdAddress() |
|
208 |
+ if err != nil { |
|
209 |
+ t.Fatalf("unexpected error: %v", err) |
|
210 |
+ } |
|
211 |
+ if expected != actual.String() { |
|
212 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
213 |
+ } |
|
214 |
+} |
|
215 |
+ |
|
216 |
+func TestEtcdAddressExplicit(t *testing.T) { |
|
217 |
+ expected := "http://external.com:12445" |
|
218 |
+ |
|
219 |
+ masterArgs := NewDefaultMasterArgs() |
|
220 |
+ masterArgs.MasterAddr.Set("http://internal.com:9012") |
|
221 |
+ masterArgs.EtcdAddr.Set(expected) |
|
222 |
+ |
|
223 |
+ actual, err := masterArgs.GetEtcdAddress() |
|
224 |
+ if err != nil { |
|
225 |
+ t.Fatalf("unexpected error: %v", err) |
|
226 |
+ } |
|
227 |
+ if expected != actual.String() { |
|
228 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
229 |
+ } |
|
230 |
+} |
|
231 |
+ |
|
232 |
+func TestEtcdBindAddressDefault(t *testing.T) { |
|
233 |
+ expected := "0.0.0.0:4001" |
|
234 |
+ |
|
235 |
+ masterArgs := NewDefaultMasterArgs() |
|
236 |
+ actual := masterArgs.GetEtcdBindAddress() |
|
237 |
+ if expected != actual { |
|
238 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
239 |
+ } |
|
240 |
+} |
|
241 |
+ |
|
242 |
+func TestEtcdPeerAddressDefault(t *testing.T) { |
|
243 |
+ expected := "0.0.0.0:7001" |
|
244 |
+ |
|
245 |
+ masterArgs := NewDefaultMasterArgs() |
|
246 |
+ actual := masterArgs.GetEtcdPeerBindAddress() |
|
247 |
+ if expected != actual { |
|
248 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
249 |
+ } |
|
250 |
+} |
|
251 |
+ |
|
252 |
+func TestEtcdBindAddressDefaultToBind(t *testing.T) { |
|
253 |
+ expected := "1.2.3.4:4001" |
|
254 |
+ |
|
255 |
+ masterArgs := NewDefaultMasterArgs() |
|
256 |
+ masterArgs.BindAddrArg.BindAddr.Set("https://1.2.3.4:8080") |
|
257 |
+ |
|
258 |
+ actual := masterArgs.GetEtcdBindAddress() |
|
259 |
+ if expected != actual { |
|
260 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
261 |
+ } |
|
262 |
+} |
|
263 |
+ |
|
264 |
+func TestMasterAddressDefaultingToBindValues(t *testing.T) { |
|
265 |
+ defaultIP, err := util.DefaultLocalIP4() |
|
266 |
+ if err != nil { |
|
267 |
+ t.Fatalf("unexpected error: %v", err) |
|
268 |
+ } |
|
269 |
+ expected := "http://" + defaultIP.String() + ":9012" |
|
270 |
+ |
|
271 |
+ masterArgs := NewDefaultMasterArgs() |
|
272 |
+ masterArgs.BindAddrArg.BindAddr.Set("http://0.0.0.0:9012") |
|
273 |
+ |
|
274 |
+ actual, err := masterArgs.GetMasterAddress() |
|
275 |
+ if err != nil { |
|
276 |
+ t.Fatalf("unexpected error: %v", err) |
|
277 |
+ } |
|
278 |
+ if expected != actual.String() { |
|
279 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
280 |
+ } |
|
281 |
+} |
|
282 |
+ |
|
283 |
+func TestMasterAddressExplicit(t *testing.T) { |
|
284 |
+ expected := "http://external.com:12445" |
|
285 |
+ |
|
286 |
+ masterArgs := NewDefaultMasterArgs() |
|
287 |
+ masterArgs.MasterAddr.Set(expected) |
|
288 |
+ |
|
289 |
+ actual, err := masterArgs.GetMasterAddress() |
|
290 |
+ if err != nil { |
|
291 |
+ t.Fatalf("unexpected error: %v", err) |
|
292 |
+ } |
|
293 |
+ if expected != actual.String() { |
|
294 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
295 |
+ } |
|
296 |
+} |
|
297 |
+ |
|
298 |
+func TestKubeClientForExternalKubernetesMasterWithNoConfig(t *testing.T) { |
|
299 |
+ expected := "https://localhost:8443" |
|
300 |
+ |
|
301 |
+ masterArgs := NewDefaultMasterArgs() |
|
302 |
+ masterArgs.MasterAddr.Set(expected) |
|
303 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
304 |
+ |
|
305 |
+ actual, err := masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
306 |
+ if err != nil { |
|
307 |
+ t.Fatalf("unexpected error: %v", err) |
|
308 |
+ } |
|
309 |
+ if expected != actual.String() { |
|
310 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
311 |
+ } |
|
312 |
+} |
|
313 |
+ |
|
314 |
+func TestKubeClientForNodeWithNoConfig(t *testing.T) { |
|
315 |
+ expected := "https://localhost:8443" |
|
316 |
+ |
|
317 |
+ masterArgs := NewDefaultMasterArgs() |
|
318 |
+ masterArgs.MasterAddr.Set(expected) |
|
319 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
320 |
+ |
|
321 |
+ actual, err := masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
322 |
+ if err != nil { |
|
323 |
+ t.Fatalf("unexpected error: %v", err) |
|
324 |
+ } |
|
325 |
+ if expected != actual.String() { |
|
326 |
+ t.Fatalf("expected %v, got %v", expected, actual) |
|
327 |
+ } |
|
328 |
+} |
|
329 |
+ |
|
330 |
+func TestKubeClientForExternalKubernetesMasterWithConfig(t *testing.T) { |
|
331 |
+ expectedServer := "https://some-other-server:1234" |
|
332 |
+ expectedUser := "myuser" |
|
333 |
+ |
|
334 |
+ masterArgs := NewDefaultMasterArgs() |
|
335 |
+ masterArgs.KubeConnectionArgs.ClientConfigLoadingRules, masterArgs.KubeConnectionArgs.ClientConfig = makeKubeconfig(expectedServer, expectedUser) |
|
336 |
+ |
|
337 |
+ actualPublic, err := masterArgs.GetKubernetesPublicAddress() |
|
338 |
+ if err != nil { |
|
339 |
+ t.Fatalf("unexpected error: %v", err) |
|
340 |
+ } |
|
341 |
+ if expectedServer != actualPublic.String() { |
|
342 |
+ t.Fatalf("expected %v, got %v", expectedServer, actualPublic) |
|
343 |
+ } |
|
344 |
+ |
|
345 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
346 |
+ |
|
347 |
+ actual, err := masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
348 |
+ if err != nil { |
|
349 |
+ t.Fatalf("unexpected error: %v", err) |
|
350 |
+ } |
|
351 |
+ if expectedServer != actual.String() { |
|
352 |
+ t.Fatalf("expected %v, got %v", expectedServer, actual) |
|
353 |
+ } |
|
354 |
+} |
|
355 |
+ |
|
356 |
+func TestKubeClientForNodeWithConfig(t *testing.T) { |
|
357 |
+ expectedServer := "https://some-other-server:1234" |
|
358 |
+ expectedUser := "myuser" |
|
359 |
+ |
|
360 |
+ nodeArgs := NewDefaultNodeArgs() |
|
361 |
+ nodeArgs.KubeConnectionArgs.ClientConfigLoadingRules, nodeArgs.KubeConnectionArgs.ClientConfig = makeKubeconfig(expectedServer, expectedUser) |
|
362 |
+ |
|
363 |
+ actual, err := nodeArgs.KubeConnectionArgs.GetKubernetesAddress(nil) |
|
364 |
+ if err != nil { |
|
365 |
+ t.Fatalf("unexpected error: %v", err) |
|
366 |
+ } |
|
367 |
+ if expectedServer != actual.String() { |
|
368 |
+ t.Fatalf("expected %v, got %v", expectedServer, actual) |
|
369 |
+ } |
|
370 |
+} |
|
371 |
+ |
|
372 |
+func TestKubeClientForExternalKubernetesMasterWithErrorKubeconfig(t *testing.T) { |
|
373 |
+ masterArgs := NewDefaultMasterArgs() |
|
374 |
+ masterArgs.KubeConnectionArgs.ClientConfigLoadingRules, masterArgs.KubeConnectionArgs.ClientConfig = makeErrorKubeconfig() |
|
375 |
+ |
|
376 |
+ // GetKubernetesPublicAddress hits the invalid kubeconfig in the fallback chain |
|
377 |
+ _, err := masterArgs.GetKubernetesPublicAddress() |
|
378 |
+ if err == nil { |
|
379 |
+ t.Fatalf("expected error, got none") |
|
380 |
+ } |
|
381 |
+ |
|
382 |
+ // GetKubernetesAddress hits the invalid kubeconfig in the fallback chain |
|
383 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
384 |
+ _, err = masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
385 |
+ if err == nil { |
|
386 |
+ t.Fatalf("expected error, got none") |
|
387 |
+ } |
|
388 |
+} |
|
389 |
+ |
|
390 |
+func TestKubeClientForExternalKubernetesMasterWithConflictingKubernetesAddress(t *testing.T) { |
|
391 |
+ expectedServer := "https://some-other-server:1234" |
|
392 |
+ expectedUser := "myuser" |
|
393 |
+ |
|
394 |
+ masterArgs := NewDefaultMasterArgs() |
|
395 |
+ // Explicitly set --kubernetes must match --kubeconfig or return an error |
|
396 |
+ masterArgs.KubeConnectionArgs.KubernetesAddr.Set(expectedServer) |
|
397 |
+ masterArgs.KubeConnectionArgs.ClientConfigLoadingRules, masterArgs.KubeConnectionArgs.ClientConfig = makeKubeconfig("https://another-server:2345", expectedUser) |
|
398 |
+ |
|
399 |
+ // GetKubernetesAddress returns the explicitly set address |
|
400 |
+ masterAddr, _ := masterArgs.GetMasterAddress() |
|
401 |
+ actual, err := masterArgs.KubeConnectionArgs.GetKubernetesAddress(masterAddr) |
|
402 |
+ if err != nil { |
|
403 |
+ t.Fatalf("unexpected error: %v", err) |
|
404 |
+ } |
|
405 |
+ if expectedServer != actual.String() { |
|
406 |
+ t.Fatalf("expected %v, got %v", expectedServer, actual) |
|
407 |
+ } |
|
408 |
+} |
|
409 |
+ |
|
410 |
+func TestKubeClientForNodeWithConflictingKubernetesAddress(t *testing.T) { |
|
411 |
+ expectedServer := "https://some-other-server:1234" |
|
412 |
+ expectedUser := "myuser" |
|
413 |
+ |
|
414 |
+ nodeArgs := NewDefaultNodeArgs() |
|
415 |
+ nodeArgs.KubeConnectionArgs.KubernetesAddr.Set(expectedServer) |
|
416 |
+ nodeArgs.KubeConnectionArgs.ClientConfigLoadingRules, nodeArgs.KubeConnectionArgs.ClientConfig = makeKubeconfig("https://another-server:2345", expectedUser) |
|
417 |
+ |
|
418 |
+ // GetKubernetesAddress returns the explicitly set address |
|
419 |
+ actualServer, err := nodeArgs.KubeConnectionArgs.GetKubernetesAddress(nil) |
|
420 |
+ if err != nil { |
|
421 |
+ t.Fatalf("unexpected error: %v", err) |
|
422 |
+ } |
|
423 |
+ if expectedServer != actualServer.String() { |
|
424 |
+ t.Fatalf("expected %v, got %v", expectedServer, actualServer) |
|
425 |
+ } |
|
426 |
+} |
|
427 |
+ |
|
428 |
+func makeEmptyKubeconfig() (clientcmd.ClientConfigLoadingRules, clientcmd.ClientConfig) { |
|
429 |
+ // Set a non-empty CommandLinePath to trigger loading |
|
430 |
+ loadingRules := clientcmd.ClientConfigLoadingRules{CommandLinePath: "specified"} |
|
431 |
+ |
|
432 |
+ clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( |
|
433 |
+ // Set empty loading rules to avoid missing file errors |
|
434 |
+ &clientcmd.ClientConfigLoadingRules{}, |
|
435 |
+ &clientcmd.ConfigOverrides{}, |
|
436 |
+ ) |
|
437 |
+ return loadingRules, clientConfig |
|
438 |
+} |
|
439 |
+ |
|
440 |
+func makeErrorKubeconfig() (clientcmd.ClientConfigLoadingRules, clientcmd.ClientConfig) { |
|
441 |
+ // Set a non-empty CommandLinePath to trigger loading |
|
442 |
+ loadingRules := clientcmd.ClientConfigLoadingRules{CommandLinePath: "missing-file"} |
|
443 |
+ |
|
444 |
+ clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( |
|
445 |
+ &loadingRules, |
|
446 |
+ &clientcmd.ConfigOverrides{}, |
|
447 |
+ ) |
|
448 |
+ return loadingRules, clientConfig |
|
449 |
+} |
|
450 |
+ |
|
451 |
+func makeKubeconfig(server, user string) (clientcmd.ClientConfigLoadingRules, clientcmd.ClientConfig) { |
|
452 |
+ // Set a non-empty CommandLinePath to trigger loading |
|
453 |
+ loadingRules := clientcmd.ClientConfigLoadingRules{CommandLinePath: "specified"} |
|
454 |
+ |
|
455 |
+ clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( |
|
456 |
+ // Set empty loading rules to avoid missing file errors |
|
457 |
+ &clientcmd.ClientConfigLoadingRules{}, |
|
458 |
+ // Override the server and user in client config to simulate loading from a file |
|
459 |
+ &clientcmd.ConfigOverrides{ |
|
460 |
+ ClusterInfo: clientcmdapi.Cluster{Server: server}, |
|
461 |
+ AuthInfo: clientcmdapi.AuthInfo{Username: user}, |
|
462 |
+ }, |
|
463 |
+ ) |
|
464 |
+ |
|
465 |
+ return loadingRules, clientConfig |
|
466 |
+} |
0 | 467 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,25 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/spf13/pflag" |
|
4 |
+ |
|
5 |
+ "github.com/openshift/origin/pkg/cmd/util/variable" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+// OriginMasterArgs is a struct that the command stores flag values into. |
|
9 |
+type ImageFormatArgs struct { |
|
10 |
+ ImageTemplate variable.ImageTemplate |
|
11 |
+} |
|
12 |
+ |
|
13 |
+func BindImageFormatArgs(args *ImageFormatArgs, flags *pflag.FlagSet, prefix string) { |
|
14 |
+ flags.StringVar(&args.ImageTemplate.Format, "images", args.ImageTemplate.Format, "When fetching images used by the cluster for important components, use this format on both master and nodes. The latest release will be used by default.") |
|
15 |
+ flags.BoolVar(&args.ImageTemplate.Latest, "latest-images", args.ImageTemplate.Latest, "If true, attempt to use the latest images for the cluster instead of the latest release.") |
|
16 |
+} |
|
17 |
+ |
|
18 |
+func NewDefaultImageFormatArgs() *ImageFormatArgs { |
|
19 |
+ config := &ImageFormatArgs{ |
|
20 |
+ ImageTemplate: variable.NewDefaultImageTemplate(), |
|
21 |
+ } |
|
22 |
+ |
|
23 |
+ return config |
|
24 |
+} |
0 | 25 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,72 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "net/url" |
|
5 |
+ |
|
6 |
+ "github.com/spf13/pflag" |
|
7 |
+ |
|
8 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
|
9 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" |
|
10 |
+ |
|
11 |
+ "github.com/openshift/origin/pkg/cmd/flagtypes" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+type KubeConnectionArgs struct { |
|
15 |
+ KubernetesAddr flagtypes.Addr |
|
16 |
+ |
|
17 |
+ // ClientConfig is used when connecting to Kubernetes from the master, or |
|
18 |
+ // when connecting to the master from a detached node. If StartKube is true, |
|
19 |
+ // this value is not used. |
|
20 |
+ ClientConfig clientcmd.ClientConfig |
|
21 |
+ // ClientConfigLoadingRules is the ruleset used to load the client config. |
|
22 |
+ // Only the CommandLinePath is expected to be used. |
|
23 |
+ ClientConfigLoadingRules clientcmd.ClientConfigLoadingRules |
|
24 |
+ |
|
25 |
+ CertArgs *CertArgs |
|
26 |
+} |
|
27 |
+ |
|
28 |
+func BindKubeConnectionArgs(args *KubeConnectionArgs, flags *pflag.FlagSet, prefix string) { |
|
29 |
+ flags.Var(&args.KubernetesAddr, prefix+"kubernetes", "The address of the Kubernetes server (host, host:port, or URL). If specified, no Kubernetes components will be started.") |
|
30 |
+ flags.StringVar(&args.ClientConfigLoadingRules.CommandLinePath, prefix+"kubeconfig", "", "Path to the kubeconfig file to use for requests to the Kubernetes API.") |
|
31 |
+} |
|
32 |
+ |
|
33 |
+func NewDefaultKubeConnectionArgs() *KubeConnectionArgs { |
|
34 |
+ config := &KubeConnectionArgs{} |
|
35 |
+ |
|
36 |
+ config.KubernetesAddr = flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default() |
|
37 |
+ config.ClientConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&config.ClientConfigLoadingRules, &clientcmd.ConfigOverrides{}) |
|
38 |
+ config.CertArgs = NewDefaultCertArgs() |
|
39 |
+ |
|
40 |
+ return config |
|
41 |
+} |
|
42 |
+ |
|
43 |
+func (args KubeConnectionArgs) GetExternalKubernetesClientConfig() (*client.Config, bool, error) { |
|
44 |
+ if len(args.ClientConfigLoadingRules.CommandLinePath) == 0 || args.ClientConfig == nil { |
|
45 |
+ return nil, false, nil |
|
46 |
+ } |
|
47 |
+ clientConfig, err := args.ClientConfig.ClientConfig() |
|
48 |
+ if err != nil { |
|
49 |
+ return nil, false, err |
|
50 |
+ } |
|
51 |
+ return clientConfig, true, nil |
|
52 |
+} |
|
53 |
+ |
|
54 |
+func (args KubeConnectionArgs) GetKubernetesAddress(defaultAddress *url.URL) (*url.URL, error) { |
|
55 |
+ if args.KubernetesAddr.Provided { |
|
56 |
+ return args.KubernetesAddr.URL, nil |
|
57 |
+ } |
|
58 |
+ |
|
59 |
+ config, ok, err := args.GetExternalKubernetesClientConfig() |
|
60 |
+ if err != nil { |
|
61 |
+ return nil, err |
|
62 |
+ } |
|
63 |
+ if ok && len(config.Host) > 0 { |
|
64 |
+ return url.Parse(config.Host) |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ if defaultAddress == nil { |
|
68 |
+ return nil, errors.New("no default KubernetesAddress present") |
|
69 |
+ } |
|
70 |
+ return defaultAddress, nil |
|
71 |
+} |
0 | 72 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,412 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ "net" |
|
5 |
+ "net/url" |
|
6 |
+ "strconv" |
|
7 |
+ |
|
8 |
+ "github.com/ghodss/yaml" |
|
9 |
+ "github.com/spf13/pflag" |
|
10 |
+ |
|
11 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
12 |
+ |
|
13 |
+ "github.com/openshift/origin/pkg/cmd/flagtypes" |
|
14 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
15 |
+ latestconfigapi "github.com/openshift/origin/pkg/cmd/server/api/latest" |
|
16 |
+ "github.com/openshift/origin/pkg/cmd/server/certs" |
|
17 |
+ cmdutil "github.com/openshift/origin/pkg/cmd/util" |
|
18 |
+) |
|
19 |
+ |
|
20 |
+// MasterArgs is a struct that the command stores flag values into. It holds a partially complete set of parameters for starting the master |
|
21 |
+// 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 |
|
22 |
+// 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 |
|
23 |
+// to starting the master. |
|
24 |
+type MasterArgs struct { |
|
25 |
+ MasterAddr flagtypes.Addr |
|
26 |
+ EtcdAddr flagtypes.Addr |
|
27 |
+ PortalNet flagtypes.IPNet |
|
28 |
+ // addresses for external clients |
|
29 |
+ MasterPublicAddr flagtypes.Addr |
|
30 |
+ AssetPublicAddr flagtypes.Addr |
|
31 |
+ KubernetesPublicAddr flagtypes.Addr |
|
32 |
+ |
|
33 |
+ // AssetBindAddr exposed for integration tests to set |
|
34 |
+ AssetBindAddr flagtypes.Addr |
|
35 |
+ // DNSBindAddr exposed for integration tests to set |
|
36 |
+ DNSBindAddr flagtypes.Addr |
|
37 |
+ |
|
38 |
+ EtcdDir string |
|
39 |
+ |
|
40 |
+ NodeList util.StringList |
|
41 |
+ |
|
42 |
+ CORSAllowedOrigins util.StringList |
|
43 |
+ |
|
44 |
+ BindAddrArg *BindAddrArg |
|
45 |
+ ImageFormatArgs *ImageFormatArgs |
|
46 |
+ KubeConnectionArgs *KubeConnectionArgs |
|
47 |
+ CertArgs *CertArgs |
|
48 |
+} |
|
49 |
+ |
|
50 |
+// BindMasterArgs binds the options to the flags with prefix + default flag names |
|
51 |
+func BindMasterArgs(args *MasterArgs, flags *pflag.FlagSet, prefix string) { |
|
52 |
+ flags.Var(&args.MasterAddr, prefix+"master", "The master address for use by OpenShift components (host, host:port, or URL). Scheme and port default to the --listen scheme and port.") |
|
53 |
+ flags.Var(&args.MasterPublicAddr, prefix+"public-master", "The master address for use by public clients, if different (host, host:port, or URL). Defaults to same as --master.") |
|
54 |
+ flags.Var(&args.EtcdAddr, prefix+"etcd", "The address of the etcd server (host, host:port, or URL). If specified, no built-in etcd will be started.") |
|
55 |
+ flags.Var(&args.KubernetesPublicAddr, prefix+"public-kubernetes", "The Kubernetes server address for use by public clients, if different. (host, host:port, or URL). Defaults to same as --kubernetes.") |
|
56 |
+ flags.Var(&args.PortalNet, prefix+"portal-net", "A CIDR notation IP range from which to assign portal IPs. This must not overlap with any IP ranges assigned to nodes for pods.") |
|
57 |
+ |
|
58 |
+ flags.StringVar(&args.EtcdDir, prefix+"etcd-dir", "openshift.local.etcd", "The etcd data directory.") |
|
59 |
+ |
|
60 |
+ flags.Var(&args.NodeList, prefix+"nodes", "The hostnames of each node. This currently must be specified up front. Comma delimited list") |
|
61 |
+ flags.Var(&args.CORSAllowedOrigins, prefix+"cors-allowed-origins", "List of allowed origins for CORS, comma separated. An allowed origin can be a regular expression to support subdomain matching. CORS is enabled for localhost, 127.0.0.1, and the asset server by default.") |
|
62 |
+} |
|
63 |
+ |
|
64 |
+// NewDefaultMasterArgs creates MasterArgs with sub-objects created and default values set. |
|
65 |
+func NewDefaultMasterArgs() *MasterArgs { |
|
66 |
+ config := &MasterArgs{ |
|
67 |
+ MasterAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
68 |
+ EtcdAddr: flagtypes.Addr{Value: "0.0.0.0:4001", DefaultScheme: "http", DefaultPort: 4001}.Default(), |
|
69 |
+ PortalNet: flagtypes.DefaultIPNet("172.30.17.0/24"), |
|
70 |
+ MasterPublicAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
71 |
+ KubernetesPublicAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(), |
|
72 |
+ AssetPublicAddr: flagtypes.Addr{Value: "localhost:8444", DefaultScheme: "https", DefaultPort: 8444, AllowPrefix: true}.Default(), |
|
73 |
+ AssetBindAddr: flagtypes.Addr{Value: "0.0.0.0:8444", DefaultScheme: "https", DefaultPort: 8444, AllowPrefix: true}.Default(), |
|
74 |
+ DNSBindAddr: flagtypes.Addr{Value: "0.0.0.0:53", DefaultScheme: "http", DefaultPort: 53, AllowPrefix: true}.Default(), |
|
75 |
+ |
|
76 |
+ BindAddrArg: NewDefaultBindAddrArg(), |
|
77 |
+ ImageFormatArgs: NewDefaultImageFormatArgs(), |
|
78 |
+ KubeConnectionArgs: NewDefaultKubeConnectionArgs(), |
|
79 |
+ CertArgs: NewDefaultCertArgs(), |
|
80 |
+ } |
|
81 |
+ |
|
82 |
+ return config |
|
83 |
+} |
|
84 |
+ |
|
85 |
+// BuildSerializeableMasterConfig takes the MasterArgs (partially complete config) and uses them along with defaulting behavior to create the fully specified |
|
86 |
+// config object for starting the master |
|
87 |
+func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig, error) { |
|
88 |
+ masterAddr, err := args.GetMasterAddress() |
|
89 |
+ if err != nil { |
|
90 |
+ return nil, err |
|
91 |
+ } |
|
92 |
+ masterPublicAddr, err := args.GetMasterPublicAddress() |
|
93 |
+ if err != nil { |
|
94 |
+ return nil, err |
|
95 |
+ } |
|
96 |
+ kubePublicAddr, err := args.GetKubernetesPublicAddress() |
|
97 |
+ if err != nil { |
|
98 |
+ return nil, err |
|
99 |
+ } |
|
100 |
+ assetPublicAddr, err := args.GetAssetPublicAddress() |
|
101 |
+ if err != nil { |
|
102 |
+ return nil, err |
|
103 |
+ } |
|
104 |
+ dnsBindAddr, err := args.GetDNSBindAddress() |
|
105 |
+ if err != nil { |
|
106 |
+ return nil, err |
|
107 |
+ } |
|
108 |
+ |
|
109 |
+ corsAllowedOrigins := []string{} |
|
110 |
+ corsAllowedOrigins = append(corsAllowedOrigins, args.CORSAllowedOrigins...) |
|
111 |
+ // always include the all-in-one server's web console as an allowed CORS origin |
|
112 |
+ // always include localhost as an allowed CORS origin |
|
113 |
+ // always include master public address as an allowed CORS origin |
|
114 |
+ for _, origin := range []string{assetPublicAddr.Host, masterPublicAddr.Host, "localhost", "127.0.0.1"} { |
|
115 |
+ corsAllowedOrigins = append(corsAllowedOrigins, origin) |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ etcdAddress, err := args.GetEtcdAddress() |
|
119 |
+ if err != nil { |
|
120 |
+ return nil, err |
|
121 |
+ } |
|
122 |
+ |
|
123 |
+ var etcdConfig *configapi.EtcdConfig |
|
124 |
+ if !args.EtcdAddr.Provided { |
|
125 |
+ etcdConfig, err = args.BuildSerializeableEtcdConfig() |
|
126 |
+ if err != nil { |
|
127 |
+ return nil, err |
|
128 |
+ } |
|
129 |
+ } |
|
130 |
+ var kubernetesMasterConfig *configapi.KubernetesMasterConfig |
|
131 |
+ if !args.KubeConnectionArgs.KubernetesAddr.Provided && len(args.KubeConnectionArgs.ClientConfigLoadingRules.CommandLinePath) == 0 { |
|
132 |
+ kubernetesMasterConfig, err = args.BuildSerializeableKubeMasterConfig() |
|
133 |
+ if err != nil { |
|
134 |
+ return nil, err |
|
135 |
+ } |
|
136 |
+ } |
|
137 |
+ |
|
138 |
+ config := &configapi.MasterConfig{ |
|
139 |
+ ServingInfo: configapi.ServingInfo{ |
|
140 |
+ BindAddress: args.BindAddrArg.BindAddr.URL.Host, |
|
141 |
+ ServerCert: certs.DefaultMasterServingCertInfo(args.CertArgs.CertDir), |
|
142 |
+ ClientCA: certs.DefaultRootCAFile(args.CertArgs.CertDir), |
|
143 |
+ }, |
|
144 |
+ CORSAllowedOrigins: corsAllowedOrigins, |
|
145 |
+ |
|
146 |
+ KubernetesMasterConfig: kubernetesMasterConfig, |
|
147 |
+ EtcdConfig: etcdConfig, |
|
148 |
+ |
|
149 |
+ OAuthConfig: &configapi.OAuthConfig{ |
|
150 |
+ ProxyCA: cmdutil.Env("OPENSHIFT_OAUTH_REQUEST_HEADER_CA_FILE", ""), |
|
151 |
+ MasterURL: masterAddr.String(), |
|
152 |
+ MasterPublicURL: masterPublicAddr.String(), |
|
153 |
+ AssetPublicURL: assetPublicAddr.String(), |
|
154 |
+ }, |
|
155 |
+ |
|
156 |
+ AssetConfig: &configapi.AssetConfig{ |
|
157 |
+ ServingInfo: configapi.ServingInfo{ |
|
158 |
+ BindAddress: args.GetAssetBindAddress(), |
|
159 |
+ ServerCert: certs.DefaultAssetServingCertInfo(args.CertArgs.CertDir), |
|
160 |
+ ClientCA: certs.DefaultRootCAFile(args.CertArgs.CertDir), |
|
161 |
+ }, |
|
162 |
+ |
|
163 |
+ LogoutURI: cmdutil.Env("OPENSHIFT_LOGOUT_URI", ""), |
|
164 |
+ MasterPublicURL: masterPublicAddr.String(), |
|
165 |
+ PublicURL: assetPublicAddr.String(), |
|
166 |
+ KubernetesPublicURL: kubePublicAddr.String(), |
|
167 |
+ }, |
|
168 |
+ |
|
169 |
+ DNSConfig: &configapi.DNSConfig{ |
|
170 |
+ BindAddress: dnsBindAddr.URL.Host, |
|
171 |
+ }, |
|
172 |
+ |
|
173 |
+ MasterClients: configapi.MasterClients{ |
|
174 |
+ DeployerKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "openshift-deployer"), |
|
175 |
+ OpenShiftLoopbackKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "openshift-client"), |
|
176 |
+ KubernetesKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "kube-client"), |
|
177 |
+ }, |
|
178 |
+ |
|
179 |
+ EtcdClientInfo: configapi.RemoteConnectionInfo{ |
|
180 |
+ URL: etcdAddress.String(), |
|
181 |
+ // TODO allow for https etcd |
|
182 |
+ CA: "", |
|
183 |
+ ClientCert: configapi.CertInfo{}, |
|
184 |
+ }, |
|
185 |
+ |
|
186 |
+ MasterAuthorizationNamespace: "master", |
|
187 |
+ OpenShiftSharedResourcesNamespace: "openshift", |
|
188 |
+ |
|
189 |
+ ImageConfig: configapi.ImageConfig{ |
|
190 |
+ Format: args.ImageFormatArgs.ImageTemplate.Format, |
|
191 |
+ Latest: args.ImageFormatArgs.ImageTemplate.Latest, |
|
192 |
+ }, |
|
193 |
+ } |
|
194 |
+ |
|
195 |
+ return config, nil |
|
196 |
+} |
|
197 |
+ |
|
198 |
+// BuildSerializeableEtcdConfig creates a fully specified etcd startup configuration based on MasterArgs |
|
199 |
+func (args MasterArgs) BuildSerializeableEtcdConfig() (*configapi.EtcdConfig, error) { |
|
200 |
+ etcdAddr, err := args.GetEtcdAddress() |
|
201 |
+ if err != nil { |
|
202 |
+ return nil, err |
|
203 |
+ } |
|
204 |
+ |
|
205 |
+ config := &configapi.EtcdConfig{ |
|
206 |
+ ServingInfo: configapi.ServingInfo{ |
|
207 |
+ BindAddress: args.GetEtcdBindAddress(), |
|
208 |
+ }, |
|
209 |
+ PeerAddress: args.GetEtcdPeerBindAddress(), |
|
210 |
+ MasterAddress: etcdAddr.Host, |
|
211 |
+ StorageDir: args.EtcdDir, |
|
212 |
+ } |
|
213 |
+ |
|
214 |
+ return config, nil |
|
215 |
+} |
|
216 |
+ |
|
217 |
+// BuildSerializeableKubeMasterConfig creates a fully specified kubernetes master startup configuration based on MasterArgs |
|
218 |
+func (args MasterArgs) BuildSerializeableKubeMasterConfig() (*configapi.KubernetesMasterConfig, error) { |
|
219 |
+ servicesSubnet := net.IPNet(args.PortalNet) |
|
220 |
+ |
|
221 |
+ config := &configapi.KubernetesMasterConfig{ |
|
222 |
+ ServicesSubnet: servicesSubnet.String(), |
|
223 |
+ StaticNodeNames: args.NodeList, |
|
224 |
+ } |
|
225 |
+ |
|
226 |
+ return config, nil |
|
227 |
+} |
|
228 |
+ |
|
229 |
+// GetServerCertHostnames returns the set of hostnames that any serving certificate for master needs to be valid for. |
|
230 |
+func (args MasterArgs) GetServerCertHostnames() (util.StringSet, error) { |
|
231 |
+ masterAddr, err := args.GetMasterAddress() |
|
232 |
+ if err != nil { |
|
233 |
+ return nil, err |
|
234 |
+ } |
|
235 |
+ masterPublicAddr, err := args.GetMasterPublicAddress() |
|
236 |
+ if err != nil { |
|
237 |
+ return nil, err |
|
238 |
+ } |
|
239 |
+ kubePublicAddr, err := args.GetKubernetesPublicAddress() |
|
240 |
+ if err != nil { |
|
241 |
+ return nil, err |
|
242 |
+ } |
|
243 |
+ assetPublicAddr, err := args.GetAssetPublicAddress() |
|
244 |
+ if err != nil { |
|
245 |
+ return nil, err |
|
246 |
+ } |
|
247 |
+ |
|
248 |
+ // 172.17.42.1 enables the router to call back out to the master |
|
249 |
+ // TODO: Remove 172.17.42.1 once we can figure out how to validate the master's cert from inside a pod, or tell pods the real IP for the master |
|
250 |
+ allHostnames := util.NewStringSet("localhost", "127.0.0.1", "172.17.42.1", masterAddr.Host, masterPublicAddr.Host, kubePublicAddr.Host, assetPublicAddr.Host) |
|
251 |
+ certHostnames := util.StringSet{} |
|
252 |
+ for hostname := range allHostnames { |
|
253 |
+ if host, _, err := net.SplitHostPort(hostname); err == nil { |
|
254 |
+ // add the hostname without the port |
|
255 |
+ certHostnames.Insert(host) |
|
256 |
+ } else { |
|
257 |
+ // add the originally specified hostname |
|
258 |
+ certHostnames.Insert(hostname) |
|
259 |
+ } |
|
260 |
+ } |
|
261 |
+ |
|
262 |
+ return certHostnames, nil |
|
263 |
+} |
|
264 |
+ |
|
265 |
+// GetMasterAddress checks for an unset master address and then attempts to use the first |
|
266 |
+// public IPv4 non-loopback address registered on this host. |
|
267 |
+// TODO: make me IPv6 safe |
|
268 |
+func (args MasterArgs) GetMasterAddress() (*url.URL, error) { |
|
269 |
+ if args.MasterAddr.Provided { |
|
270 |
+ return args.MasterAddr.URL, nil |
|
271 |
+ } |
|
272 |
+ |
|
273 |
+ // If the user specifies a bind address, and the master is not provided, use the bind port by default |
|
274 |
+ port := args.MasterAddr.Port |
|
275 |
+ if args.BindAddrArg.BindAddr.Provided { |
|
276 |
+ port = args.BindAddrArg.BindAddr.Port |
|
277 |
+ } |
|
278 |
+ |
|
279 |
+ // If the user specifies a bind address, and the master is not provided, use the bind scheme by default |
|
280 |
+ scheme := args.MasterAddr.URL.Scheme |
|
281 |
+ if args.BindAddrArg.BindAddr.Provided { |
|
282 |
+ scheme = args.BindAddrArg.BindAddr.URL.Scheme |
|
283 |
+ } |
|
284 |
+ |
|
285 |
+ addr := "" |
|
286 |
+ if ip, err := cmdutil.DefaultLocalIP4(); err == nil { |
|
287 |
+ addr = ip.String() |
|
288 |
+ } else if err == cmdutil.ErrorNoDefaultIP { |
|
289 |
+ addr = "127.0.0.1" |
|
290 |
+ } else if err != nil { |
|
291 |
+ return nil, fmt.Errorf("Unable to find a public IP address: %v", err) |
|
292 |
+ } |
|
293 |
+ |
|
294 |
+ masterAddr := scheme + "://" + net.JoinHostPort(addr, strconv.Itoa(port)) |
|
295 |
+ return url.Parse(masterAddr) |
|
296 |
+} |
|
297 |
+ |
|
298 |
+func (args MasterArgs) GetDNSBindAddress() (flagtypes.Addr, error) { |
|
299 |
+ if args.DNSBindAddr.Provided { |
|
300 |
+ return args.DNSBindAddr, nil |
|
301 |
+ } |
|
302 |
+ dnsAddr := flagtypes.Addr{Value: args.BindAddrArg.BindAddr.Host, DefaultPort: 53}.Default() |
|
303 |
+ return dnsAddr, nil |
|
304 |
+} |
|
305 |
+ |
|
306 |
+func (args MasterArgs) GetMasterPublicAddress() (*url.URL, error) { |
|
307 |
+ if args.MasterPublicAddr.Provided { |
|
308 |
+ return args.MasterPublicAddr.URL, nil |
|
309 |
+ } |
|
310 |
+ |
|
311 |
+ return args.GetMasterAddress() |
|
312 |
+} |
|
313 |
+ |
|
314 |
+func (args MasterArgs) GetEtcdBindAddress() string { |
|
315 |
+ // Derive the etcd bind address by using the bind address and the default etcd port |
|
316 |
+ return net.JoinHostPort(args.BindAddrArg.BindAddr.Host, strconv.Itoa(args.EtcdAddr.DefaultPort)) |
|
317 |
+} |
|
318 |
+ |
|
319 |
+func (args MasterArgs) GetEtcdPeerBindAddress() string { |
|
320 |
+ // Derive the etcd peer address by using the bind address and the default etcd peering port |
|
321 |
+ return net.JoinHostPort(args.BindAddrArg.BindAddr.Host, "7001") |
|
322 |
+} |
|
323 |
+ |
|
324 |
+func (args MasterArgs) GetEtcdAddress() (*url.URL, error) { |
|
325 |
+ if args.EtcdAddr.Provided { |
|
326 |
+ return args.EtcdAddr.URL, nil |
|
327 |
+ } |
|
328 |
+ |
|
329 |
+ // Etcd should be reachable on the same address that the master is (for simplicity) |
|
330 |
+ masterAddr, err := args.GetMasterAddress() |
|
331 |
+ if err != nil { |
|
332 |
+ return nil, err |
|
333 |
+ } |
|
334 |
+ |
|
335 |
+ etcdAddr := net.JoinHostPort(getHost(*masterAddr), strconv.Itoa(args.EtcdAddr.DefaultPort)) |
|
336 |
+ return url.Parse(args.EtcdAddr.DefaultScheme + "://" + etcdAddr) |
|
337 |
+} |
|
338 |
+ |
|
339 |
+func (args MasterArgs) GetKubernetesPublicAddress() (*url.URL, error) { |
|
340 |
+ if args.KubernetesPublicAddr.Provided { |
|
341 |
+ return args.KubernetesPublicAddr.URL, nil |
|
342 |
+ } |
|
343 |
+ if args.KubeConnectionArgs.KubernetesAddr.Provided { |
|
344 |
+ return args.KubeConnectionArgs.KubernetesAddr.URL, nil |
|
345 |
+ } |
|
346 |
+ config, ok, err := args.KubeConnectionArgs.GetExternalKubernetesClientConfig() |
|
347 |
+ if err != nil { |
|
348 |
+ return nil, err |
|
349 |
+ } |
|
350 |
+ if ok && len(config.Host) > 0 { |
|
351 |
+ return url.Parse(config.Host) |
|
352 |
+ } |
|
353 |
+ |
|
354 |
+ return args.GetMasterPublicAddress() |
|
355 |
+} |
|
356 |
+ |
|
357 |
+func (args MasterArgs) GetAssetPublicAddress() (*url.URL, error) { |
|
358 |
+ if args.AssetPublicAddr.Provided { |
|
359 |
+ return args.AssetPublicAddr.URL, nil |
|
360 |
+ } |
|
361 |
+ // Derive the asset public address by incrementing the master public address port by 1 |
|
362 |
+ // TODO: derive the scheme/port from the asset bind scheme/port once that is settable via the command line |
|
363 |
+ t, err := args.GetMasterPublicAddress() |
|
364 |
+ if err != nil { |
|
365 |
+ return nil, err |
|
366 |
+ } |
|
367 |
+ assetPublicAddr := *t |
|
368 |
+ assetPublicAddr.Host = net.JoinHostPort(getHost(assetPublicAddr), strconv.Itoa(getPort(assetPublicAddr)+1)) |
|
369 |
+ |
|
370 |
+ return &assetPublicAddr, nil |
|
371 |
+} |
|
372 |
+ |
|
373 |
+func (args MasterArgs) GetAssetBindAddress() string { |
|
374 |
+ if args.AssetBindAddr.Provided { |
|
375 |
+ return args.AssetBindAddr.URL.Host |
|
376 |
+ } |
|
377 |
+ // Derive the asset bind address by incrementing the master bind address port by 1 |
|
378 |
+ return net.JoinHostPort(args.BindAddrArg.BindAddr.Host, strconv.Itoa(args.BindAddrArg.BindAddr.Port+1)) |
|
379 |
+} |
|
380 |
+ |
|
381 |
+func getHost(theURL url.URL) string { |
|
382 |
+ host, _, err := net.SplitHostPort(theURL.Host) |
|
383 |
+ if err != nil { |
|
384 |
+ return theURL.Host |
|
385 |
+ } |
|
386 |
+ |
|
387 |
+ return host |
|
388 |
+} |
|
389 |
+ |
|
390 |
+func getPort(theURL url.URL) int { |
|
391 |
+ _, port, err := net.SplitHostPort(theURL.Host) |
|
392 |
+ if err != nil { |
|
393 |
+ return 0 |
|
394 |
+ } |
|
395 |
+ |
|
396 |
+ intport, _ := strconv.Atoi(port) |
|
397 |
+ return intport |
|
398 |
+} |
|
399 |
+ |
|
400 |
+// WriteMaster serializes the config to yaml. |
|
401 |
+func WriteMaster(config *configapi.MasterConfig) ([]byte, error) { |
|
402 |
+ json, err := latestconfigapi.Codec.Encode(config) |
|
403 |
+ if err != nil { |
|
404 |
+ return nil, err |
|
405 |
+ } |
|
406 |
+ content, err := yaml.JSONToYAML(json) |
|
407 |
+ if err != nil { |
|
408 |
+ return nil, err |
|
409 |
+ } |
|
410 |
+ return content, nil |
|
411 |
+} |
0 | 412 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,127 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ "net" |
|
5 |
+ "net/url" |
|
6 |
+ "os/exec" |
|
7 |
+ "strconv" |
|
8 |
+ "strings" |
|
9 |
+ |
|
10 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports" |
|
11 |
+ "github.com/ghodss/yaml" |
|
12 |
+ "github.com/golang/glog" |
|
13 |
+ "github.com/spf13/pflag" |
|
14 |
+ |
|
15 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
16 |
+ latestconfigapi "github.com/openshift/origin/pkg/cmd/server/api/latest" |
|
17 |
+ "github.com/openshift/origin/pkg/cmd/server/certs" |
|
18 |
+ cmdutil "github.com/openshift/origin/pkg/cmd/util" |
|
19 |
+) |
|
20 |
+ |
|
21 |
+// NodeArgs is a struct that the command stores flag values into. It holds a partially complete set of parameters for starting the master |
|
22 |
+// 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 |
|
23 |
+// 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 |
|
24 |
+// to starting the master. |
|
25 |
+type NodeArgs struct { |
|
26 |
+ NodeName string |
|
27 |
+ |
|
28 |
+ AllowDisabledDocker bool |
|
29 |
+ VolumeDir string |
|
30 |
+ |
|
31 |
+ DefaultKubernetesURL url.URL |
|
32 |
+ ClusterDomain string |
|
33 |
+ ClusterDNS net.IP |
|
34 |
+ |
|
35 |
+ BindAddrArg *BindAddrArg |
|
36 |
+ ImageFormatArgs *ImageFormatArgs |
|
37 |
+ KubeConnectionArgs *KubeConnectionArgs |
|
38 |
+ CertArgs *CertArgs |
|
39 |
+} |
|
40 |
+ |
|
41 |
+// BindNodeArgs binds the options to the flags with prefix + default flag names |
|
42 |
+func BindNodeArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string) { |
|
43 |
+ flags.StringVar(&args.VolumeDir, prefix+"volume-dir", "openshift.local.volumes", "The volume storage directory.") |
|
44 |
+ // TODO rename this node-name and recommend hostname -f |
|
45 |
+ flags.StringVar(&args.NodeName, prefix+"hostname", args.NodeName, "The hostname to identify this node with the master.") |
|
46 |
+} |
|
47 |
+ |
|
48 |
+// NewDefaultNodeArgs creates NodeArgs with sub-objects created and default values set. |
|
49 |
+func NewDefaultNodeArgs() *NodeArgs { |
|
50 |
+ hostname, err := defaultHostname() |
|
51 |
+ if err != nil { |
|
52 |
+ hostname = "localhost" |
|
53 |
+ glog.Warningf("Unable to lookup hostname, using %q: %v", hostname, err) |
|
54 |
+ } |
|
55 |
+ |
|
56 |
+ var dnsIP net.IP |
|
57 |
+ if clusterDNS := cmdutil.Env("OPENSHIFT_DNS_ADDR", ""); len(clusterDNS) > 0 { |
|
58 |
+ dnsIP = net.ParseIP(clusterDNS) |
|
59 |
+ } |
|
60 |
+ |
|
61 |
+ return &NodeArgs{ |
|
62 |
+ NodeName: hostname, |
|
63 |
+ |
|
64 |
+ ClusterDomain: cmdutil.Env("OPENSHIFT_DNS_DOMAIN", "local"), |
|
65 |
+ ClusterDNS: dnsIP, |
|
66 |
+ |
|
67 |
+ BindAddrArg: NewDefaultBindAddrArg(), |
|
68 |
+ ImageFormatArgs: NewDefaultImageFormatArgs(), |
|
69 |
+ KubeConnectionArgs: NewDefaultKubeConnectionArgs(), |
|
70 |
+ CertArgs: NewDefaultCertArgs(), |
|
71 |
+ } |
|
72 |
+} |
|
73 |
+ |
|
74 |
+// BuildSerializeableNodeConfig takes the NodeArgs (partially complete config) and uses them along with defaulting behavior to create the fully specified |
|
75 |
+// config object for starting the node |
|
76 |
+func (args NodeArgs) BuildSerializeableNodeConfig() (*configapi.NodeConfig, error) { |
|
77 |
+ var dnsIP string |
|
78 |
+ if len(args.ClusterDNS) > 0 { |
|
79 |
+ dnsIP = args.ClusterDNS.String() |
|
80 |
+ } |
|
81 |
+ |
|
82 |
+ config := &configapi.NodeConfig{ |
|
83 |
+ NodeName: args.NodeName, |
|
84 |
+ |
|
85 |
+ ServingInfo: configapi.ServingInfo{ |
|
86 |
+ BindAddress: net.JoinHostPort(args.BindAddrArg.BindAddr.Host, strconv.Itoa(ports.KubeletPort)), |
|
87 |
+ ServerCert: certs.DefaultNodeServingCertInfo(args.CertArgs.CertDir, args.NodeName), |
|
88 |
+ }, |
|
89 |
+ |
|
90 |
+ VolumeDirectory: args.VolumeDir, |
|
91 |
+ NetworkContainerImage: args.ImageFormatArgs.ImageTemplate.ExpandOrDie("pod"), |
|
92 |
+ AllowDisabledDocker: args.AllowDisabledDocker, |
|
93 |
+ |
|
94 |
+ DNSDomain: args.ClusterDomain, |
|
95 |
+ DNSIP: dnsIP, |
|
96 |
+ |
|
97 |
+ MasterKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "node-"+args.NodeName), |
|
98 |
+ } |
|
99 |
+ |
|
100 |
+ return config, nil |
|
101 |
+} |
|
102 |
+ |
|
103 |
+// WriteNode serializes the config to yaml. |
|
104 |
+func WriteNode(config *configapi.NodeConfig) ([]byte, error) { |
|
105 |
+ json, err := latestconfigapi.Codec.Encode(config) |
|
106 |
+ if err != nil { |
|
107 |
+ return nil, err |
|
108 |
+ } |
|
109 |
+ content, err := yaml.JSONToYAML(json) |
|
110 |
+ if err != nil { |
|
111 |
+ return nil, err |
|
112 |
+ } |
|
113 |
+ return content, nil |
|
114 |
+} |
|
115 |
+ |
|
116 |
+// defaultHostname returns the default hostname for this system. |
|
117 |
+func defaultHostname() (string, error) { |
|
118 |
+ |
|
119 |
+ // Note: We use exec here instead of os.Hostname() because we |
|
120 |
+ // want the FQDN, and this is the easiest way to get it. |
|
121 |
+ fqdn, err := exec.Command("hostname", "-f").Output() |
|
122 |
+ if err != nil { |
|
123 |
+ return "", fmt.Errorf("Couldn't determine hostname: %v", err) |
|
124 |
+ } |
|
125 |
+ return strings.TrimSpace(string(fqdn)), nil |
|
126 |
+} |
0 | 127 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,222 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "net" |
|
6 |
+ "strings" |
|
7 |
+ |
|
8 |
+ "github.com/coreos/go-systemd/daemon" |
|
9 |
+ "github.com/golang/glog" |
|
10 |
+ "github.com/spf13/cobra" |
|
11 |
+ |
|
12 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
13 |
+ |
|
14 |
+ "github.com/openshift/origin/pkg/cmd/server/certs" |
|
15 |
+ |
|
16 |
+ _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit" |
|
17 |
+ _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/limitranger" |
|
18 |
+ _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/exists" |
|
19 |
+ _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcedefaults" |
|
20 |
+ _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcequota" |
|
21 |
+) |
|
22 |
+ |
|
23 |
+type AllInOneOptions struct { |
|
24 |
+ MasterArgs *MasterArgs |
|
25 |
+ NodeArgs *NodeArgs |
|
26 |
+ |
|
27 |
+ WriteConfigOnly bool |
|
28 |
+ MasterConfigFile string |
|
29 |
+ NodeConfigFile string |
|
30 |
+} |
|
31 |
+ |
|
32 |
+const longAllInOneCommandDesc = ` |
|
33 |
+Start an OpenShift all-in-one server |
|
34 |
+ |
|
35 |
+This command helps you launch an OpenShift all-in-one server, which allows |
|
36 |
+you to run all of the components of an OpenShift system on a server with Docker. Running |
|
37 |
+ |
|
38 |
+ $ openshift start |
|
39 |
+ |
|
40 |
+will start OpenShift listening on all interfaces, launch an etcd server to store persistent |
|
41 |
+data, and launch the Kubernetes system components. The server will run in the foreground until |
|
42 |
+you terminate the process. This command delegates to "openshift start master" and |
|
43 |
+"openshift start node". |
|
44 |
+ |
|
45 |
+ |
|
46 |
+Note: starting OpenShift without passing the --master address will attempt to find the IP |
|
47 |
+address that will be visible inside running Docker containers. This is not always successful, |
|
48 |
+so if you have problems tell OpenShift what public address it will be via --master=<ip>. |
|
49 |
+ |
|
50 |
+You may also pass --etcd=<address> to connect to an external etcd server. |
|
51 |
+ |
|
52 |
+You may also pass --kubeconfig=<path> to connect to an external Kubernetes cluster. |
|
53 |
+` |
|
54 |
+ |
|
55 |
+// NewCommandStartMaster provides a CLI handler for 'start' command |
|
56 |
+func NewCommandStartAllInOne() (*cobra.Command, *AllInOneOptions) { |
|
57 |
+ options := &AllInOneOptions{} |
|
58 |
+ |
|
59 |
+ cmd := &cobra.Command{ |
|
60 |
+ Use: "start", |
|
61 |
+ Short: "Launch OpenShift All-In-One", |
|
62 |
+ Long: longAllInOneCommandDesc, |
|
63 |
+ Run: func(c *cobra.Command, args []string) { |
|
64 |
+ if err := options.Complete(); err != nil { |
|
65 |
+ fmt.Println(err.Error()) |
|
66 |
+ c.Help() |
|
67 |
+ return |
|
68 |
+ } |
|
69 |
+ if err := options.Validate(args); err != nil { |
|
70 |
+ fmt.Println(err.Error()) |
|
71 |
+ c.Help() |
|
72 |
+ return |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ if err := options.StartAllInOne(); err != nil { |
|
76 |
+ glog.Fatal(err) |
|
77 |
+ } |
|
78 |
+ }, |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ flags := cmd.Flags() |
|
82 |
+ |
|
83 |
+ flags.BoolVar(&options.WriteConfigOnly, "write-config", false, "Indicates that the command should build the configuration from command-line arguments, write it to the locations specified by --master-config and --node-config, and exit.") |
|
84 |
+ flags.StringVar(&options.MasterConfigFile, "master-config", "", "Location of the master configuration file to run from, or write to (when used with --write-config). When running from configuration files, all other command-line arguments are ignored.") |
|
85 |
+ flags.StringVar(&options.NodeConfigFile, "node-config", "", "Location of the node configuration file to run from, or write to (when used with --write-config). When running from configuration files, all other command-line arguments are ignored.") |
|
86 |
+ |
|
87 |
+ masterArgs, nodeArgs, bindAddrArg, imageFormatArgs, kubeConnectionArgs, certArgs := GetAllInOneArgs() |
|
88 |
+ options.MasterArgs, options.NodeArgs = masterArgs, nodeArgs |
|
89 |
+ // by default, all-in-ones all disabled docker. Set it here so that if we allow it to be bound later, bindings take precendence |
|
90 |
+ options.NodeArgs.AllowDisabledDocker = true |
|
91 |
+ |
|
92 |
+ BindMasterArgs(masterArgs, flags, "") |
|
93 |
+ BindNodeArgs(nodeArgs, flags, "") |
|
94 |
+ BindBindAddrArg(bindAddrArg, flags, "") |
|
95 |
+ BindImageFormatArgs(imageFormatArgs, flags, "") |
|
96 |
+ BindKubeConnectionArgs(kubeConnectionArgs, flags, "") |
|
97 |
+ BindCertArgs(certArgs, flags, "") |
|
98 |
+ |
|
99 |
+ startMaster, _ := NewCommandStartMaster() |
|
100 |
+ startNode, _ := NewCommandStartNode() |
|
101 |
+ cmd.AddCommand(startMaster) |
|
102 |
+ cmd.AddCommand(startNode) |
|
103 |
+ |
|
104 |
+ return cmd, options |
|
105 |
+} |
|
106 |
+ |
|
107 |
+// GetAllInOneArgs makes sure that the node and master args that should be shared, are shared |
|
108 |
+func GetAllInOneArgs() (*MasterArgs, *NodeArgs, *BindAddrArg, *ImageFormatArgs, *KubeConnectionArgs, *CertArgs) { |
|
109 |
+ masterArgs := NewDefaultMasterArgs() |
|
110 |
+ nodeArgs := NewDefaultNodeArgs() |
|
111 |
+ |
|
112 |
+ bindAddrArg := NewDefaultBindAddrArg() |
|
113 |
+ masterArgs.BindAddrArg = bindAddrArg |
|
114 |
+ nodeArgs.BindAddrArg = bindAddrArg |
|
115 |
+ |
|
116 |
+ imageFormatArgs := NewDefaultImageFormatArgs() |
|
117 |
+ masterArgs.ImageFormatArgs = imageFormatArgs |
|
118 |
+ nodeArgs.ImageFormatArgs = imageFormatArgs |
|
119 |
+ |
|
120 |
+ kubeConnectionArgs := NewDefaultKubeConnectionArgs() |
|
121 |
+ masterArgs.KubeConnectionArgs = kubeConnectionArgs |
|
122 |
+ nodeArgs.KubeConnectionArgs = kubeConnectionArgs |
|
123 |
+ |
|
124 |
+ certArgs := NewDefaultCertArgs() |
|
125 |
+ masterArgs.CertArgs = certArgs |
|
126 |
+ nodeArgs.CertArgs = certArgs |
|
127 |
+ kubeConnectionArgs.CertArgs = certArgs |
|
128 |
+ |
|
129 |
+ return masterArgs, nodeArgs, bindAddrArg, imageFormatArgs, kubeConnectionArgs, certArgs |
|
130 |
+} |
|
131 |
+ |
|
132 |
+func (o AllInOneOptions) Validate(args []string) error { |
|
133 |
+ if len(args) != 0 { |
|
134 |
+ return errors.New("no arguments are supported for start") |
|
135 |
+ } |
|
136 |
+ if o.WriteConfigOnly { |
|
137 |
+ if len(o.MasterConfigFile) == 0 { |
|
138 |
+ return errors.New("--master-config is required if --write-config is true") |
|
139 |
+ } |
|
140 |
+ if len(o.NodeConfigFile) == 0 { |
|
141 |
+ return errors.New("--node-config is required if --write-config is true") |
|
142 |
+ } |
|
143 |
+ } |
|
144 |
+ |
|
145 |
+ return nil |
|
146 |
+} |
|
147 |
+ |
|
148 |
+func (o AllInOneOptions) Complete() error { |
|
149 |
+ nodeList := util.NewStringSet(strings.ToLower(o.NodeArgs.NodeName)) |
|
150 |
+ // take everything toLower |
|
151 |
+ for _, s := range o.MasterArgs.NodeList { |
|
152 |
+ nodeList.Insert(strings.ToLower(s)) |
|
153 |
+ } |
|
154 |
+ o.MasterArgs.NodeList = nodeList.List() |
|
155 |
+ |
|
156 |
+ o.NodeArgs.NodeName = strings.ToLower(o.NodeArgs.NodeName) |
|
157 |
+ |
|
158 |
+ return nil |
|
159 |
+} |
|
160 |
+ |
|
161 |
+// StartAllInOne: |
|
162 |
+// 1. Creates the signer certificate if needed |
|
163 |
+// 2. Calls RunMaster |
|
164 |
+// 3. Calls RunNode |
|
165 |
+// 4. If only writing configs, it exits |
|
166 |
+// 5. Waits forever |
|
167 |
+func (o AllInOneOptions) StartAllInOne() error { |
|
168 |
+ if !o.WriteConfigOnly { |
|
169 |
+ glog.Infof("Starting an OpenShift all-in-one") |
|
170 |
+ } |
|
171 |
+ |
|
172 |
+ // if either one of these wants to mint certs, make sure the signer is present BEFORE they start up to make sure they always share |
|
173 |
+ if o.MasterArgs.CertArgs.CreateCerts || o.NodeArgs.CertArgs.CreateCerts { |
|
174 |
+ signerOptions := &certs.CreateSignerCertOptions{ |
|
175 |
+ CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
176 |
+ KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
177 |
+ SerialFile: certs.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
178 |
+ Name: certs.DefaultSignerName(), |
|
179 |
+ } |
|
180 |
+ |
|
181 |
+ if _, err := signerOptions.CreateSignerCert(); err != nil { |
|
182 |
+ return err |
|
183 |
+ } |
|
184 |
+ } |
|
185 |
+ |
|
186 |
+ masterOptions := MasterOptions{o.MasterArgs, o.WriteConfigOnly, o.MasterConfigFile} |
|
187 |
+ |
|
188 |
+ masterAddr, err := masterOptions.MasterArgs.GetMasterAddress() |
|
189 |
+ if err != nil { |
|
190 |
+ return nil |
|
191 |
+ } |
|
192 |
+ |
|
193 |
+ // in the all-in-one, default kubernetes URL to the master's address |
|
194 |
+ o.NodeArgs.DefaultKubernetesURL = *masterAddr |
|
195 |
+ |
|
196 |
+ // in the all-in-one, default ClusterDNS to the master's address |
|
197 |
+ if host, _, err := net.SplitHostPort(masterAddr.Host); err == nil { |
|
198 |
+ if ip := net.ParseIP(host); ip != nil { |
|
199 |
+ o.NodeArgs.ClusterDNS = ip |
|
200 |
+ } |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ nodeOptions := NodeOptions{o.NodeArgs, o.WriteConfigOnly, o.NodeConfigFile} |
|
204 |
+ |
|
205 |
+ if err := masterOptions.RunMaster(); err != nil { |
|
206 |
+ return err |
|
207 |
+ } |
|
208 |
+ |
|
209 |
+ if err := nodeOptions.RunNode(); err != nil { |
|
210 |
+ return err |
|
211 |
+ } |
|
212 |
+ |
|
213 |
+ if o.WriteConfigOnly { |
|
214 |
+ return nil |
|
215 |
+ } |
|
216 |
+ |
|
217 |
+ daemon.SdNotify("READY=1") |
|
218 |
+ select {} |
|
219 |
+ |
|
220 |
+ return nil |
|
221 |
+} |
0 | 222 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,349 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "io/ioutil" |
|
6 |
+ "net/http" |
|
7 |
+ _ "net/http/pprof" |
|
8 |
+ "strings" |
|
9 |
+ |
|
10 |
+ "github.com/coreos/go-systemd/daemon" |
|
11 |
+ "github.com/golang/glog" |
|
12 |
+ "github.com/spf13/cobra" |
|
13 |
+ |
|
14 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
15 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities" |
|
16 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" |
|
17 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
18 |
+ |
|
19 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
20 |
+ configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" |
|
21 |
+ "github.com/openshift/origin/pkg/cmd/server/certs" |
|
22 |
+ "github.com/openshift/origin/pkg/cmd/server/etcd" |
|
23 |
+ "github.com/openshift/origin/pkg/cmd/server/kubernetes" |
|
24 |
+ "github.com/openshift/origin/pkg/cmd/server/origin" |
|
25 |
+ cmdutil "github.com/openshift/origin/pkg/cmd/util" |
|
26 |
+) |
|
27 |
+ |
|
28 |
+type MasterOptions struct { |
|
29 |
+ MasterArgs *MasterArgs |
|
30 |
+ |
|
31 |
+ WriteConfigOnly bool |
|
32 |
+ ConfigFile string |
|
33 |
+} |
|
34 |
+ |
|
35 |
+const longMasterCommandDesc = ` |
|
36 |
+Start an OpenShift master |
|
37 |
+ |
|
38 |
+This command helps you launch an OpenShift master. Running |
|
39 |
+ |
|
40 |
+ $ openshift start master |
|
41 |
+ |
|
42 |
+will start an OpenShift master listening on all interfaces, launch an etcd server to store |
|
43 |
+persistent data, and launch the Kubernetes system components. The server will run in the |
|
44 |
+foreground until you terminate the process. |
|
45 |
+ |
|
46 |
+Note: starting OpenShift without passing the --master address will attempt to find the IP |
|
47 |
+address that will be visible inside running Docker containers. This is not always successful, |
|
48 |
+so if you have problems tell OpenShift what public address it will be via --master=<ip>. |
|
49 |
+ |
|
50 |
+You may also pass an optional argument to the start command to start OpenShift in one of the |
|
51 |
+following roles: |
|
52 |
+ |
|
53 |
+ $ openshift start master --nodes=<host1,host2,host3,...> |
|
54 |
+ |
|
55 |
+ Launches the server and control plane for OpenShift. You may pass a list of the node |
|
56 |
+ hostnames you want to use, or create nodes via the REST API or 'openshift kube'. |
|
57 |
+ |
|
58 |
+You may also pass --etcd=<address> to connect to an external etcd server. |
|
59 |
+ |
|
60 |
+You may also pass --kubeconfig=<path> to connect to an external Kubernetes cluster. |
|
61 |
+` |
|
62 |
+ |
|
63 |
+// NewCommandStartMaster provides a CLI handler for 'start' command |
|
64 |
+func NewCommandStartMaster() (*cobra.Command, *MasterOptions) { |
|
65 |
+ options := &MasterOptions{} |
|
66 |
+ |
|
67 |
+ cmd := &cobra.Command{ |
|
68 |
+ Use: "master", |
|
69 |
+ Short: "Launch OpenShift master", |
|
70 |
+ Long: longMasterCommandDesc, |
|
71 |
+ Run: func(c *cobra.Command, args []string) { |
|
72 |
+ if err := options.Complete(); err != nil { |
|
73 |
+ fmt.Println(err.Error()) |
|
74 |
+ c.Help() |
|
75 |
+ return |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+ if err := options.Validate(args); err != nil { |
|
79 |
+ fmt.Println(err.Error()) |
|
80 |
+ c.Help() |
|
81 |
+ return |
|
82 |
+ } |
|
83 |
+ |
|
84 |
+ if err := options.StartMaster(); err != nil { |
|
85 |
+ glog.Fatal(err) |
|
86 |
+ } |
|
87 |
+ }, |
|
88 |
+ } |
|
89 |
+ |
|
90 |
+ flags := cmd.Flags() |
|
91 |
+ |
|
92 |
+ flags.BoolVar(&options.WriteConfigOnly, "write-config", false, "Indicates that the command should build the configuration from command-line arguments, write it to the location specified by --config, and exit.") |
|
93 |
+ flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from, or write to (when used with --write-config). When running from a configuration file, all other command-line arguments are ignored.") |
|
94 |
+ |
|
95 |
+ options.MasterArgs = NewDefaultMasterArgs() |
|
96 |
+ // make sure that KubeConnectionArgs and MasterArgs use the same CertArgs for this command |
|
97 |
+ options.MasterArgs.KubeConnectionArgs.CertArgs = options.MasterArgs.CertArgs |
|
98 |
+ |
|
99 |
+ BindMasterArgs(options.MasterArgs, flags, "") |
|
100 |
+ BindBindAddrArg(options.MasterArgs.BindAddrArg, flags, "") |
|
101 |
+ BindImageFormatArgs(options.MasterArgs.ImageFormatArgs, flags, "") |
|
102 |
+ BindKubeConnectionArgs(options.MasterArgs.KubeConnectionArgs, flags, "") |
|
103 |
+ BindCertArgs(options.MasterArgs.CertArgs, flags, "") |
|
104 |
+ |
|
105 |
+ return cmd, options |
|
106 |
+} |
|
107 |
+ |
|
108 |
+func (o MasterOptions) Validate(args []string) error { |
|
109 |
+ if len(args) != 0 { |
|
110 |
+ return errors.New("no arguments are supported for start master") |
|
111 |
+ } |
|
112 |
+ if o.WriteConfigOnly { |
|
113 |
+ if len(o.ConfigFile) == 0 { |
|
114 |
+ return errors.New("--config is required if --write-config is true") |
|
115 |
+ } |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ return nil |
|
119 |
+} |
|
120 |
+ |
|
121 |
+func (o MasterOptions) Complete() error { |
|
122 |
+ nodeList := util.NewStringSet() |
|
123 |
+ // take everything toLower |
|
124 |
+ for _, s := range o.MasterArgs.NodeList { |
|
125 |
+ nodeList.Insert(strings.ToLower(s)) |
|
126 |
+ } |
|
127 |
+ |
|
128 |
+ o.MasterArgs.NodeList = nodeList.List() |
|
129 |
+ |
|
130 |
+ return nil |
|
131 |
+} |
|
132 |
+ |
|
133 |
+// StartMaster calls RunMaster and then waits forever |
|
134 |
+func (o MasterOptions) StartMaster() error { |
|
135 |
+ if err := o.RunMaster(); err != nil { |
|
136 |
+ return err |
|
137 |
+ } |
|
138 |
+ |
|
139 |
+ if o.WriteConfigOnly { |
|
140 |
+ return nil |
|
141 |
+ } |
|
142 |
+ |
|
143 |
+ daemon.SdNotify("READY=1") |
|
144 |
+ select {} |
|
145 |
+ |
|
146 |
+ return nil |
|
147 |
+} |
|
148 |
+ |
|
149 |
+// RunMaster takes the options and: |
|
150 |
+// 1. Creates certs if needed |
|
151 |
+// 2. Reads fully specified master config OR builds a fully specified master config from the args |
|
152 |
+// 3. Writes the fully specified master config and exits if needed |
|
153 |
+// 4. Starts the master based on the fully specified config |
|
154 |
+func (o MasterOptions) RunMaster() error { |
|
155 |
+ startUsingConfigFile := !o.WriteConfigOnly && (len(o.ConfigFile) > 0) |
|
156 |
+ mintCerts := o.MasterArgs.CertArgs.CreateCerts && !startUsingConfigFile |
|
157 |
+ |
|
158 |
+ if mintCerts { |
|
159 |
+ if err := o.CreateCerts(); err != nil { |
|
160 |
+ return nil |
|
161 |
+ } |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ var masterConfig *configapi.MasterConfig |
|
165 |
+ var err error |
|
166 |
+ if startUsingConfigFile { |
|
167 |
+ masterConfig, err = ReadMasterConfig(o.ConfigFile) |
|
168 |
+ } else { |
|
169 |
+ masterConfig, err = o.MasterArgs.BuildSerializeableMasterConfig() |
|
170 |
+ } |
|
171 |
+ if err != nil { |
|
172 |
+ return err |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ if o.WriteConfigOnly { |
|
176 |
+ content, err := WriteMaster(masterConfig) |
|
177 |
+ if err != nil { |
|
178 |
+ return err |
|
179 |
+ } |
|
180 |
+ if err := ioutil.WriteFile(o.ConfigFile, content, 0644); err != nil { |
|
181 |
+ return err |
|
182 |
+ } |
|
183 |
+ return nil |
|
184 |
+ } |
|
185 |
+ |
|
186 |
+ if err := StartMaster(masterConfig); err != nil { |
|
187 |
+ return err |
|
188 |
+ } |
|
189 |
+ |
|
190 |
+ return nil |
|
191 |
+} |
|
192 |
+ |
|
193 |
+func (o MasterOptions) CreateCerts() error { |
|
194 |
+ signerName := certs.DefaultSignerName() |
|
195 |
+ hostnames, err := o.MasterArgs.GetServerCertHostnames() |
|
196 |
+ if err != nil { |
|
197 |
+ return err |
|
198 |
+ } |
|
199 |
+ mintAllCertsOptions := certs.CreateAllCertsOptions{ |
|
200 |
+ CertDir: o.MasterArgs.CertArgs.CertDir, |
|
201 |
+ SignerName: signerName, |
|
202 |
+ Hostnames: hostnames.List(), |
|
203 |
+ NodeList: o.MasterArgs.NodeList, |
|
204 |
+ } |
|
205 |
+ if err := mintAllCertsOptions.CreateAllCerts(); err != nil { |
|
206 |
+ return err |
|
207 |
+ } |
|
208 |
+ |
|
209 |
+ rootCAFile := certs.DefaultRootCAFile(o.MasterArgs.CertArgs.CertDir) |
|
210 |
+ masterAddr, err := o.MasterArgs.GetMasterAddress() |
|
211 |
+ if err != nil { |
|
212 |
+ return err |
|
213 |
+ } |
|
214 |
+ publicMasterAddr, err := o.MasterArgs.GetMasterPublicAddress() |
|
215 |
+ if err != nil { |
|
216 |
+ return err |
|
217 |
+ } |
|
218 |
+ for _, clientCertInfo := range certs.DefaultClientCerts(o.MasterArgs.CertArgs.CertDir) { |
|
219 |
+ createKubeConfigOptions := certs.CreateKubeConfigOptions{ |
|
220 |
+ APIServerURL: masterAddr.String(), |
|
221 |
+ PublicAPIServerURL: publicMasterAddr.String(), |
|
222 |
+ APIServerCAFile: rootCAFile, |
|
223 |
+ ServerNick: "master", |
|
224 |
+ |
|
225 |
+ CertFile: clientCertInfo.CertLocation.CertFile, |
|
226 |
+ KeyFile: clientCertInfo.CertLocation.KeyFile, |
|
227 |
+ UserNick: clientCertInfo.SubDir, |
|
228 |
+ |
|
229 |
+ KubeConfigFile: certs.DefaultKubeConfigFilename(o.MasterArgs.CertArgs.CertDir, clientCertInfo.SubDir), |
|
230 |
+ } |
|
231 |
+ |
|
232 |
+ if _, err := createKubeConfigOptions.CreateKubeConfig(); err != nil { |
|
233 |
+ return err |
|
234 |
+ } |
|
235 |
+ } |
|
236 |
+ |
|
237 |
+ return nil |
|
238 |
+} |
|
239 |
+ |
|
240 |
+func ReadMasterConfig(filename string) (*configapi.MasterConfig, error) { |
|
241 |
+ data, err := ioutil.ReadFile(filename) |
|
242 |
+ if err != nil { |
|
243 |
+ return nil, err |
|
244 |
+ } |
|
245 |
+ |
|
246 |
+ config := &configapi.MasterConfig{} |
|
247 |
+ |
|
248 |
+ if err := configapilatest.Codec.DecodeInto(data, config); err != nil { |
|
249 |
+ return nil, err |
|
250 |
+ } |
|
251 |
+ return config, nil |
|
252 |
+} |
|
253 |
+ |
|
254 |
+func StartMaster(openshiftMasterConfig *configapi.MasterConfig) error { |
|
255 |
+ glog.Infof("Starting an OpenShift master, reachable at %s (etcd: %s)", openshiftMasterConfig.ServingInfo.BindAddress, openshiftMasterConfig.EtcdClientInfo.URL) |
|
256 |
+ glog.Infof("OpenShift master public address is %s", openshiftMasterConfig.AssetConfig.MasterPublicURL) |
|
257 |
+ |
|
258 |
+ if openshiftMasterConfig.EtcdConfig != nil { |
|
259 |
+ etcdConfig := &etcd.Config{ |
|
260 |
+ BindAddr: openshiftMasterConfig.EtcdConfig.ServingInfo.BindAddress, |
|
261 |
+ PeerBindAddr: openshiftMasterConfig.EtcdConfig.PeerAddress, |
|
262 |
+ MasterAddr: openshiftMasterConfig.EtcdConfig.MasterAddress, |
|
263 |
+ EtcdDir: openshiftMasterConfig.EtcdConfig.StorageDir, |
|
264 |
+ } |
|
265 |
+ |
|
266 |
+ etcdConfig.Run() |
|
267 |
+ } |
|
268 |
+ |
|
269 |
+ if cmdutil.Env("OPENSHIFT_PROFILE", "") == "web" { |
|
270 |
+ go func() { |
|
271 |
+ glog.Infof("Starting profiling endpoint at http://127.0.0.1:6060/debug/pprof/") |
|
272 |
+ glog.Fatal(http.ListenAndServe("127.0.0.1:6060", nil)) |
|
273 |
+ }() |
|
274 |
+ } |
|
275 |
+ |
|
276 |
+ // Allow privileged containers |
|
277 |
+ // TODO: make this configurable and not the default https://github.com/openshift/origin/issues/662 |
|
278 |
+ capabilities.Initialize(capabilities.Capabilities{ |
|
279 |
+ AllowPrivileged: true, |
|
280 |
+ }) |
|
281 |
+ |
|
282 |
+ openshiftConfig, err := origin.BuildMasterConfig(*openshiftMasterConfig) |
|
283 |
+ if err != nil { |
|
284 |
+ return err |
|
285 |
+ } |
|
286 |
+ // must start policy caching immediately |
|
287 |
+ openshiftConfig.RunPolicyCache() |
|
288 |
+ |
|
289 |
+ authConfig, err := origin.BuildAuthConfig(*openshiftMasterConfig) |
|
290 |
+ if err != nil { |
|
291 |
+ return err |
|
292 |
+ } |
|
293 |
+ |
|
294 |
+ if openshiftMasterConfig.KubernetesMasterConfig != nil { |
|
295 |
+ glog.Infof("Static Nodes: %v", openshiftMasterConfig.KubernetesMasterConfig.StaticNodeNames) |
|
296 |
+ |
|
297 |
+ kubeConfig, err := kubernetes.BuildKubernetesMasterConfig(*openshiftMasterConfig, openshiftConfig.RequestContextMapper, openshiftConfig.KubeClient()) |
|
298 |
+ if err != nil { |
|
299 |
+ return err |
|
300 |
+ } |
|
301 |
+ kubeConfig.EnsurePortalFlags() |
|
302 |
+ |
|
303 |
+ openshiftConfig.Run([]origin.APIInstaller{kubeConfig}, []origin.APIInstaller{authConfig}) |
|
304 |
+ |
|
305 |
+ kubeConfig.RunScheduler() |
|
306 |
+ kubeConfig.RunReplicationController() |
|
307 |
+ kubeConfig.RunEndpointController() |
|
308 |
+ kubeConfig.RunMinionController() |
|
309 |
+ kubeConfig.RunResourceQuotaManager() |
|
310 |
+ |
|
311 |
+ } else { |
|
312 |
+ _, kubeConfig, err := configapi.GetKubeClient(openshiftMasterConfig.MasterClients.KubernetesKubeConfig) |
|
313 |
+ if err != nil { |
|
314 |
+ return err |
|
315 |
+ } |
|
316 |
+ |
|
317 |
+ proxy := &kubernetes.ProxyConfig{ |
|
318 |
+ ClientConfig: kubeConfig, |
|
319 |
+ } |
|
320 |
+ |
|
321 |
+ openshiftConfig.Run([]origin.APIInstaller{proxy}, []origin.APIInstaller{authConfig}) |
|
322 |
+ } |
|
323 |
+ |
|
324 |
+ // TODO: recording should occur in individual components |
|
325 |
+ record.StartRecording(openshiftConfig.KubeClient().Events(""), kapi.EventSource{Component: "master"}) |
|
326 |
+ |
|
327 |
+ glog.Infof("Using images from %q", openshiftConfig.ImageFor("<component>")) |
|
328 |
+ |
|
329 |
+ if openshiftMasterConfig.DNSConfig != nil { |
|
330 |
+ openshiftConfig.RunDNSServer() |
|
331 |
+ } |
|
332 |
+ if openshiftMasterConfig.AssetConfig != nil { |
|
333 |
+ openshiftConfig.RunAssetServer() |
|
334 |
+ } |
|
335 |
+ openshiftConfig.RunBuildController() |
|
336 |
+ openshiftConfig.RunBuildPodController() |
|
337 |
+ openshiftConfig.RunBuildImageChangeTriggerController() |
|
338 |
+ if err := openshiftConfig.RunDeploymentController(); err != nil { |
|
339 |
+ return err |
|
340 |
+ } |
|
341 |
+ openshiftConfig.RunDeployerPodController() |
|
342 |
+ openshiftConfig.RunDeploymentConfigController() |
|
343 |
+ openshiftConfig.RunDeploymentConfigChangeController() |
|
344 |
+ openshiftConfig.RunDeploymentImageChangeTriggerController() |
|
345 |
+ openshiftConfig.RunProjectAuthorizationCache() |
|
346 |
+ |
|
347 |
+ return nil |
|
348 |
+} |
0 | 349 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,267 @@ |
0 |
+package start |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "io/ioutil" |
|
6 |
+ "net/http" |
|
7 |
+ _ "net/http/pprof" |
|
8 |
+ "path" |
|
9 |
+ "path/filepath" |
|
10 |
+ "strings" |
|
11 |
+ |
|
12 |
+ "github.com/coreos/go-systemd/daemon" |
|
13 |
+ "github.com/golang/glog" |
|
14 |
+ "github.com/spf13/cobra" |
|
15 |
+ |
|
16 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
17 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" |
|
18 |
+ "github.com/openshift/origin/pkg/cmd/server/kubernetes" |
|
19 |
+ |
|
20 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
21 |
+ configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" |
|
22 |
+ "github.com/openshift/origin/pkg/cmd/server/certs" |
|
23 |
+ cmdutil "github.com/openshift/origin/pkg/cmd/util" |
|
24 |
+ "github.com/openshift/origin/pkg/cmd/util/docker" |
|
25 |
+) |
|
26 |
+ |
|
27 |
+type NodeOptions struct { |
|
28 |
+ NodeArgs *NodeArgs |
|
29 |
+ |
|
30 |
+ WriteConfigOnly bool |
|
31 |
+ ConfigFile string |
|
32 |
+} |
|
33 |
+ |
|
34 |
+const longNodeCommandDesc = ` |
|
35 |
+Start an OpenShift node |
|
36 |
+This command helps you launch an OpenShift node. Running |
|
37 |
+ |
|
38 |
+ $ openshift start node --master=<masterIP> |
|
39 |
+ |
|
40 |
+will start an OpenShift node that attempts to connect to the master on the provided IP. The |
|
41 |
+node will run in the foreground until you terminate the process. |
|
42 |
+` |
|
43 |
+ |
|
44 |
+// NewCommandStartMaster provides a CLI handler for 'start' command |
|
45 |
+func NewCommandStartNode() (*cobra.Command, *NodeOptions) { |
|
46 |
+ options := &NodeOptions{} |
|
47 |
+ |
|
48 |
+ cmd := &cobra.Command{ |
|
49 |
+ Use: "node", |
|
50 |
+ Short: "Launch OpenShift node", |
|
51 |
+ Long: longNodeCommandDesc, |
|
52 |
+ Run: func(c *cobra.Command, args []string) { |
|
53 |
+ if err := options.Complete(); err != nil { |
|
54 |
+ fmt.Println(err.Error()) |
|
55 |
+ c.Help() |
|
56 |
+ return |
|
57 |
+ } |
|
58 |
+ if err := options.Validate(args); err != nil { |
|
59 |
+ fmt.Println(err.Error()) |
|
60 |
+ c.Help() |
|
61 |
+ return |
|
62 |
+ } |
|
63 |
+ |
|
64 |
+ if err := options.StartNode(); err != nil { |
|
65 |
+ glog.Fatal(err) |
|
66 |
+ } |
|
67 |
+ }, |
|
68 |
+ } |
|
69 |
+ |
|
70 |
+ flags := cmd.Flags() |
|
71 |
+ |
|
72 |
+ flags.BoolVar(&options.WriteConfigOnly, "write-config", false, "Indicates that the command should build the configuration from command-line arguments, write it to the location specified by --config, and exit.") |
|
73 |
+ flags.StringVar(&options.ConfigFile, "config", "", "Location of the node configuration file to run from, or write to (when used with --write-config). When running from a configuration file, all other command-line arguments are ignored.") |
|
74 |
+ |
|
75 |
+ options.NodeArgs = NewDefaultNodeArgs() |
|
76 |
+ // make sure that KubeConnectionArgs and NodeArgs use the same CertArgs for this command |
|
77 |
+ options.NodeArgs.KubeConnectionArgs.CertArgs = options.NodeArgs.CertArgs |
|
78 |
+ |
|
79 |
+ BindNodeArgs(options.NodeArgs, flags, "") |
|
80 |
+ BindBindAddrArg(options.NodeArgs.BindAddrArg, flags, "") |
|
81 |
+ BindImageFormatArgs(options.NodeArgs.ImageFormatArgs, flags, "") |
|
82 |
+ BindKubeConnectionArgs(options.NodeArgs.KubeConnectionArgs, flags, "") |
|
83 |
+ BindCertArgs(options.NodeArgs.CertArgs, flags, "") |
|
84 |
+ |
|
85 |
+ return cmd, options |
|
86 |
+} |
|
87 |
+ |
|
88 |
+func (o NodeOptions) Validate(args []string) error { |
|
89 |
+ if len(args) != 0 { |
|
90 |
+ return errors.New("no arguments are supported for start node") |
|
91 |
+ } |
|
92 |
+ if o.WriteConfigOnly { |
|
93 |
+ if len(o.ConfigFile) == 0 { |
|
94 |
+ return errors.New("--config is required if --write-config is true") |
|
95 |
+ } |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ return nil |
|
99 |
+} |
|
100 |
+ |
|
101 |
+func (o NodeOptions) Complete() error { |
|
102 |
+ o.NodeArgs.NodeName = strings.ToLower(o.NodeArgs.NodeName) |
|
103 |
+ |
|
104 |
+ return nil |
|
105 |
+} |
|
106 |
+ |
|
107 |
+// StartNode calls RunNode and then waits forever |
|
108 |
+func (o NodeOptions) StartNode() error { |
|
109 |
+ if err := o.RunNode(); err != nil { |
|
110 |
+ return err |
|
111 |
+ } |
|
112 |
+ |
|
113 |
+ if o.WriteConfigOnly { |
|
114 |
+ return nil |
|
115 |
+ } |
|
116 |
+ |
|
117 |
+ daemon.SdNotify("READY=1") |
|
118 |
+ select {} |
|
119 |
+ |
|
120 |
+ return nil |
|
121 |
+} |
|
122 |
+ |
|
123 |
+// RunNode takes the options and: |
|
124 |
+// 1. Creates certs if needed |
|
125 |
+// 2. Reads fully specified node config OR builds a fully specified node config from the args |
|
126 |
+// 3. Writes the fully specified node config and exits if needed |
|
127 |
+// 4. Starts the node based on the fully specified config |
|
128 |
+func (o NodeOptions) RunNode() error { |
|
129 |
+ startUsingConfigFile := !o.WriteConfigOnly && (len(o.ConfigFile) > 0) |
|
130 |
+ mintCerts := o.NodeArgs.CertArgs.CreateCerts && !startUsingConfigFile |
|
131 |
+ |
|
132 |
+ if mintCerts { |
|
133 |
+ if err := o.CreateCerts(); err != nil { |
|
134 |
+ return nil |
|
135 |
+ } |
|
136 |
+ } |
|
137 |
+ |
|
138 |
+ var nodeConfig *configapi.NodeConfig |
|
139 |
+ var err error |
|
140 |
+ if startUsingConfigFile { |
|
141 |
+ nodeConfig, err = ReadNodeConfig(o.ConfigFile) |
|
142 |
+ } else { |
|
143 |
+ nodeConfig, err = o.NodeArgs.BuildSerializeableNodeConfig() |
|
144 |
+ } |
|
145 |
+ if err != nil { |
|
146 |
+ return err |
|
147 |
+ } |
|
148 |
+ |
|
149 |
+ if o.WriteConfigOnly { |
|
150 |
+ content, err := WriteNode(nodeConfig) |
|
151 |
+ if err != nil { |
|
152 |
+ return err |
|
153 |
+ } |
|
154 |
+ if err := ioutil.WriteFile(o.ConfigFile, content, 0644); err != nil { |
|
155 |
+ return err |
|
156 |
+ } |
|
157 |
+ return nil |
|
158 |
+ } |
|
159 |
+ |
|
160 |
+ _, kubeClientConfig, err := configapi.GetKubeClient(nodeConfig.MasterKubeConfig) |
|
161 |
+ if err != nil { |
|
162 |
+ return err |
|
163 |
+ } |
|
164 |
+ glog.Infof("Starting an OpenShift node, connecting to %s", kubeClientConfig.Host) |
|
165 |
+ |
|
166 |
+ if cmdutil.Env("OPENSHIFT_PROFILE", "") == "web" { |
|
167 |
+ go func() { |
|
168 |
+ glog.Infof("Starting profiling endpoint at http://127.0.0.1:6060/debug/pprof/") |
|
169 |
+ glog.Fatal(http.ListenAndServe("127.0.0.1:6060", nil)) |
|
170 |
+ }() |
|
171 |
+ } |
|
172 |
+ |
|
173 |
+ if err := StartNode(*nodeConfig); err != nil { |
|
174 |
+ return err |
|
175 |
+ } |
|
176 |
+ |
|
177 |
+ return nil |
|
178 |
+} |
|
179 |
+ |
|
180 |
+func (o NodeOptions) CreateCerts() error { |
|
181 |
+ username := "node-" + o.NodeArgs.NodeName |
|
182 |
+ signerOptions := &certs.CreateSignerCertOptions{ |
|
183 |
+ CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
184 |
+ KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
185 |
+ SerialFile: certs.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
186 |
+ Name: certs.DefaultSignerName(), |
|
187 |
+ } |
|
188 |
+ if _, err := signerOptions.CreateSignerCert(); err != nil { |
|
189 |
+ return err |
|
190 |
+ } |
|
191 |
+ getSignerOptions := &certs.GetSignerCertOptions{ |
|
192 |
+ CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
193 |
+ KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
194 |
+ SerialFile: certs.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), |
|
195 |
+ } |
|
196 |
+ |
|
197 |
+ mintNodeClientCert := certs.CreateNodeClientCertOptions{ |
|
198 |
+ GetSignerCertOptions: getSignerOptions, |
|
199 |
+ CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, username), |
|
200 |
+ KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, username), |
|
201 |
+ NodeName: o.NodeArgs.NodeName, |
|
202 |
+ } |
|
203 |
+ if _, err := mintNodeClientCert.CreateNodeClientCert(); err != nil { |
|
204 |
+ return err |
|
205 |
+ } |
|
206 |
+ |
|
207 |
+ masterAddr, err := o.NodeArgs.KubeConnectionArgs.GetKubernetesAddress(&o.NodeArgs.DefaultKubernetesURL) |
|
208 |
+ if err != nil { |
|
209 |
+ return err |
|
210 |
+ } |
|
211 |
+ |
|
212 |
+ createKubeConfigOptions := certs.CreateKubeConfigOptions{ |
|
213 |
+ APIServerURL: masterAddr.String(), |
|
214 |
+ APIServerCAFile: getSignerOptions.CertFile, |
|
215 |
+ ServerNick: "master", |
|
216 |
+ |
|
217 |
+ CertFile: mintNodeClientCert.CertFile, |
|
218 |
+ KeyFile: mintNodeClientCert.KeyFile, |
|
219 |
+ UserNick: username, |
|
220 |
+ |
|
221 |
+ KubeConfigFile: path.Join(filepath.Dir(mintNodeClientCert.CertFile), ".kubeconfig"), |
|
222 |
+ } |
|
223 |
+ if _, err := createKubeConfigOptions.CreateKubeConfig(); err != nil { |
|
224 |
+ return err |
|
225 |
+ } |
|
226 |
+ |
|
227 |
+ return nil |
|
228 |
+} |
|
229 |
+ |
|
230 |
+func ReadNodeConfig(filename string) (*configapi.NodeConfig, error) { |
|
231 |
+ data, err := ioutil.ReadFile(filename) |
|
232 |
+ if err != nil { |
|
233 |
+ return nil, err |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ config := &configapi.NodeConfig{} |
|
237 |
+ |
|
238 |
+ if err := configapilatest.Codec.DecodeInto(data, config); err != nil { |
|
239 |
+ return nil, err |
|
240 |
+ } |
|
241 |
+ return config, nil |
|
242 |
+} |
|
243 |
+ |
|
244 |
+func StartNode(config configapi.NodeConfig) error { |
|
245 |
+ if config.RecordEvents { |
|
246 |
+ kubeClient, _, err := configapi.GetKubeClient(config.MasterKubeConfig) |
|
247 |
+ if err != nil { |
|
248 |
+ return err |
|
249 |
+ } |
|
250 |
+ |
|
251 |
+ // TODO: recording should occur in individual components |
|
252 |
+ record.StartRecording(kubeClient.Events(""), kapi.EventSource{Component: "node"}) |
|
253 |
+ } |
|
254 |
+ |
|
255 |
+ nodeConfig, err := kubernetes.BuildKubernetesNodeConfig(config) |
|
256 |
+ if err != nil { |
|
257 |
+ return err |
|
258 |
+ } |
|
259 |
+ |
|
260 |
+ nodeConfig.EnsureVolumeDir() |
|
261 |
+ nodeConfig.EnsureDocker(docker.NewHelper()) |
|
262 |
+ nodeConfig.RunProxy() |
|
263 |
+ nodeConfig.RunKubelet() |
|
264 |
+ |
|
265 |
+ return nil |
|
266 |
+} |
... | ... |
@@ -4,8 +4,17 @@ import ( |
4 | 4 |
"fmt" |
5 | 5 |
"os" |
6 | 6 |
"regexp" |
7 |
+ "strconv" |
|
7 | 8 |
) |
8 | 9 |
|
10 |
+func EnvInt(key string, defaultValue int32, minValue int32) int32 { |
|
11 |
+ value, err := strconv.ParseInt(Env(key, fmt.Sprintf("%d", defaultValue)), 10, 32) |
|
12 |
+ if err != nil || int32(value) < minValue { |
|
13 |
+ return defaultValue |
|
14 |
+ } |
|
15 |
+ return int32(value) |
|
16 |
+} |
|
17 |
+ |
|
9 | 18 |
// Env returns an environment variable or a default value if not specified. |
10 | 19 |
func Env(key string, defaultValue string) string { |
11 | 20 |
val := os.Getenv(key) |
... | ... |
@@ -9,14 +9,14 @@ import ( |
9 | 9 |
) |
10 | 10 |
|
11 | 11 |
// TryListen tries to open a connection on the given port and returns true if it succeeded. |
12 |
-func TryListen(hostPort string) bool { |
|
12 |
+func TryListen(hostPort string) (bool, error) { |
|
13 | 13 |
l, err := net.Listen("tcp", hostPort) |
14 | 14 |
if err != nil { |
15 | 15 |
glog.V(5).Infof("Failure while checking listen on %s: %v", err) |
16 |
- return false |
|
16 |
+ return false, err |
|
17 | 17 |
} |
18 | 18 |
defer l.Close() |
19 |
- return true |
|
19 |
+ return true, nil |
|
20 | 20 |
} |
21 | 21 |
|
22 | 22 |
// WaitForDial attempts to connect to the given address, closing and returning nil on the first successful connection. |
... | ... |
@@ -17,21 +17,21 @@ import ( |
17 | 17 |
) |
18 | 18 |
|
19 | 19 |
func TestRestrictedAccessForProjectAdmins(t *testing.T) { |
20 |
- startConfig, err := StartTestMaster() |
|
20 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
21 | 21 |
if err != nil { |
22 | 22 |
t.Fatalf("unexpected error: %v", err) |
23 | 23 |
} |
24 | 24 |
|
25 |
- openshiftClient, openshiftClientConfig, err := startConfig.GetOpenshiftClient() |
|
25 |
+ clusterAdminClient, _, clusterAdminClientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
26 | 26 |
if err != nil { |
27 | 27 |
t.Errorf("unexpected error: %v", err) |
28 | 28 |
} |
29 | 29 |
|
30 |
- haroldClient, err := CreateNewProject(openshiftClient, *openshiftClientConfig, "hammer-project", "harold") |
|
30 |
+ haroldClient, err := CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") |
|
31 | 31 |
if err != nil { |
32 | 32 |
t.Errorf("unexpected error: %v", err) |
33 | 33 |
} |
34 |
- markClient, err := CreateNewProject(openshiftClient, *openshiftClientConfig, "mallet-project", "mark") |
|
34 |
+ markClient, err := CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") |
|
35 | 35 |
if err != nil { |
36 | 36 |
t.Errorf("unexpected error: %v", err) |
37 | 37 |
} |
... | ... |
@@ -81,12 +81,12 @@ func TestRestrictedAccessForProjectAdmins(t *testing.T) { |
81 | 81 |
} |
82 | 82 |
|
83 | 83 |
func TestOnlyResolveRolesForBindingsThatMatter(t *testing.T) { |
84 |
- startConfig, err := StartTestMaster() |
|
84 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
85 | 85 |
if err != nil { |
86 | 86 |
t.Fatalf("unexpected error: %v", err) |
87 | 87 |
} |
88 | 88 |
|
89 |
- openshiftClient, _, err := startConfig.GetOpenshiftClient() |
|
89 |
+ clusterAdminClient, _, _, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
90 | 90 |
if err != nil { |
91 | 91 |
t.Errorf("unexpected error: %v", err) |
92 | 92 |
} |
... | ... |
@@ -95,14 +95,14 @@ func TestOnlyResolveRolesForBindingsThatMatter(t *testing.T) { |
95 | 95 |
RoleNamespace: "master", |
96 | 96 |
RoleName: "view", |
97 | 97 |
BindingNamespace: "master", |
98 |
- Client: openshiftClient, |
|
98 |
+ Client: clusterAdminClient, |
|
99 | 99 |
Users: []string{"anypassword:valerie"}, |
100 | 100 |
} |
101 | 101 |
if err := addValerie.Run(); err != nil { |
102 | 102 |
t.Errorf("unexpected error: %v", err) |
103 | 103 |
} |
104 | 104 |
|
105 |
- if err = openshiftClient.Roles("master").Delete("view"); err != nil { |
|
105 |
+ if err = clusterAdminClient.Roles("master").Delete("view"); err != nil { |
|
106 | 106 |
t.Errorf("unexpected error: %v", err) |
107 | 107 |
} |
108 | 108 |
|
... | ... |
@@ -110,7 +110,7 @@ func TestOnlyResolveRolesForBindingsThatMatter(t *testing.T) { |
110 | 110 |
RoleNamespace: "master", |
111 | 111 |
RoleName: "edit", |
112 | 112 |
BindingNamespace: "master", |
113 |
- Client: openshiftClient, |
|
113 |
+ Client: clusterAdminClient, |
|
114 | 114 |
Users: []string{"anypassword:edgar"}, |
115 | 115 |
} |
116 | 116 |
if err := addEdgar.Run(); err != nil { |
... | ... |
@@ -126,7 +126,7 @@ func TestOnlyResolveRolesForBindingsThatMatter(t *testing.T) { |
126 | 126 |
|
127 | 127 |
// TODO this list should start collapsing as we continue to tighten access on generated system ids |
128 | 128 |
var globalClusterAdminUsers = util.NewStringSet("system:kube-client", "system:openshift-client", "system:openshift-deployer") |
129 |
-var globalClusterAdminGroups = util.NewStringSet("system:cluster-admins") |
|
129 |
+var globalClusterAdminGroups = util.NewStringSet("system:cluster-admins", "system:nodes") |
|
130 | 130 |
|
131 | 131 |
type resourceAccessReviewTest struct { |
132 | 132 |
clientInterface client.ResourceAccessReviewInterface |
... | ... |
@@ -156,21 +156,21 @@ func (test resourceAccessReviewTest) run(t *testing.T) { |
156 | 156 |
} |
157 | 157 |
|
158 | 158 |
func TestResourceAccessReview(t *testing.T) { |
159 |
- startConfig, err := StartTestMaster() |
|
159 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
160 | 160 |
if err != nil { |
161 | 161 |
t.Fatalf("unexpected error: %v", err) |
162 | 162 |
} |
163 | 163 |
|
164 |
- openshiftClient, openshiftClientConfig, err := startConfig.GetOpenshiftClient() |
|
164 |
+ clusterAdminClient, _, clusterAdminClientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
165 | 165 |
if err != nil { |
166 | 166 |
t.Errorf("unexpected error: %v", err) |
167 | 167 |
} |
168 | 168 |
|
169 |
- haroldClient, err := CreateNewProject(openshiftClient, *openshiftClientConfig, "hammer-project", "harold") |
|
169 |
+ haroldClient, err := CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") |
|
170 | 170 |
if err != nil { |
171 | 171 |
t.Errorf("unexpected error: %v", err) |
172 | 172 |
} |
173 |
- markClient, err := CreateNewProject(openshiftClient, *openshiftClientConfig, "mallet-project", "mark") |
|
173 |
+ markClient, err := CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") |
|
174 | 174 |
if err != nil { |
175 | 175 |
t.Errorf("unexpected error: %v", err) |
176 | 176 |
} |
... | ... |
@@ -239,7 +239,7 @@ func TestResourceAccessReview(t *testing.T) { |
239 | 239 |
// a cluster-admin should be able to make global access review requests |
240 | 240 |
{ |
241 | 241 |
test := resourceAccessReviewTest{ |
242 |
- clientInterface: openshiftClient.RootResourceAccessReviews(), |
|
242 |
+ clientInterface: clusterAdminClient.RootResourceAccessReviews(), |
|
243 | 243 |
review: requestWhoCanViewDeployments, |
244 | 244 |
response: authorizationapi.ResourceAccessReviewResponse{ |
245 | 245 |
Users: globalClusterAdminUsers, |
... | ... |
@@ -278,21 +278,21 @@ func (test subjectAccessReviewTest) run(t *testing.T) { |
278 | 278 |
} |
279 | 279 |
|
280 | 280 |
func TestSubjectAccessReview(t *testing.T) { |
281 |
- startConfig, err := StartTestMaster() |
|
281 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
282 | 282 |
if err != nil { |
283 | 283 |
t.Fatalf("unexpected error: %v", err) |
284 | 284 |
} |
285 | 285 |
|
286 |
- openshiftClient, openshiftClientConfig, err := startConfig.GetOpenshiftClient() |
|
286 |
+ clusterAdminClient, _, clusterAdminClientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
287 | 287 |
if err != nil { |
288 | 288 |
t.Errorf("unexpected error: %v", err) |
289 | 289 |
} |
290 | 290 |
|
291 |
- haroldClient, err := CreateNewProject(openshiftClient, *openshiftClientConfig, "hammer-project", "harold") |
|
291 |
+ haroldClient, err := CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") |
|
292 | 292 |
if err != nil { |
293 | 293 |
t.Errorf("unexpected error: %v", err) |
294 | 294 |
} |
295 |
- markClient, err := CreateNewProject(openshiftClient, *openshiftClientConfig, "mallet-project", "mark") |
|
295 |
+ markClient, err := CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") |
|
296 | 296 |
if err != nil { |
297 | 297 |
t.Errorf("unexpected error: %v", err) |
298 | 298 |
} |
... | ... |
@@ -368,7 +368,7 @@ func TestSubjectAccessReview(t *testing.T) { |
368 | 368 |
|
369 | 369 |
askCanClusterAdminsCreateProject := &authorizationapi.SubjectAccessReview{Groups: util.NewStringSet("system:cluster-admins"), Verb: "create", Resource: "projects"} |
370 | 370 |
subjectAccessReviewTest{ |
371 |
- clientInterface: openshiftClient.RootSubjectAccessReviews(), |
|
371 |
+ clientInterface: clusterAdminClient.RootSubjectAccessReviews(), |
|
372 | 372 |
review: askCanClusterAdminsCreateProject, |
373 | 373 |
response: authorizationapi.SubjectAccessReviewResponse{ |
374 | 374 |
Allowed: true, |
... | ... |
@@ -15,17 +15,17 @@ import ( |
15 | 15 |
) |
16 | 16 |
|
17 | 17 |
func TestAuthenticatedUsersAgainstOpenshiftNamespace(t *testing.T) { |
18 |
- startConfig, err := StartTestMaster() |
|
18 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
19 | 19 |
if err != nil { |
20 | 20 |
t.Fatalf("unexpected error: %v", err) |
21 | 21 |
} |
22 | 22 |
|
23 |
- _, openshiftClientConfig, err := startConfig.GetOpenshiftClient() |
|
23 |
+ _, _, clusterAdminClientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
24 | 24 |
if err != nil { |
25 | 25 |
t.Errorf("unexpected error: %v", err) |
26 | 26 |
} |
27 | 27 |
|
28 |
- valerieClientConfig := *openshiftClientConfig |
|
28 |
+ valerieClientConfig := *clusterAdminClientConfig |
|
29 | 29 |
valerieClientConfig.Username = "" |
30 | 30 |
valerieClientConfig.Password = "" |
31 | 31 |
valerieClientConfig.BearerToken = "" |
... | ... |
@@ -12,14 +12,11 @@ import ( |
12 | 12 |
) |
13 | 13 |
|
14 | 14 |
func TestDNS(t *testing.T) { |
15 |
- _, err := StartTestAllInOne() |
|
15 |
+ masterConfig, _, err := StartTestAllInOne() |
|
16 | 16 |
if err != nil { |
17 | 17 |
t.Fatalf("unexpected error: %v", err) |
18 | 18 |
} |
19 | 19 |
|
20 |
- // ugly... |
|
21 |
- server := "127.0.0.1:8053" |
|
22 |
- |
|
23 | 20 |
// verify service DNS entry is visible |
24 | 21 |
stop := make(chan struct{}) |
25 | 22 |
util.Until(func() { |
... | ... |
@@ -27,7 +24,7 @@ func TestDNS(t *testing.T) { |
27 | 27 |
MsgHdr: dns.MsgHdr{Id: dns.Id(), RecursionDesired: true}, |
28 | 28 |
Question: []dns.Question{{"kubernetes.default.local.", dns.TypeA, dns.ClassINET}}, |
29 | 29 |
} |
30 |
- in, err := dns.Exchange(m1, server) |
|
30 |
+ in, err := dns.Exchange(m1, masterConfig.DNSConfig.BindAddress) |
|
31 | 31 |
if err != nil { |
32 | 32 |
t.Logf("unexpected error: %v", err) |
33 | 33 |
return |
... | ... |
@@ -52,7 +49,7 @@ func TestDNS(t *testing.T) { |
52 | 52 |
MsgHdr: dns.MsgHdr{Id: dns.Id(), RecursionDesired: true}, |
53 | 53 |
Question: []dns.Question{{"foo.kubernetes.default.local.", dns.TypeA, dns.ClassINET}}, |
54 | 54 |
} |
55 |
- in, err := dns.Exchange(m1, server) |
|
55 |
+ in, err := dns.Exchange(m1, masterConfig.DNSConfig.BindAddress) |
|
56 | 56 |
if err != nil { |
57 | 57 |
t.Fatalf("unexpected error: %v", err) |
58 | 58 |
} |
... | ... |
@@ -73,7 +70,7 @@ func TestDNS(t *testing.T) { |
73 | 73 |
MsgHdr: dns.MsgHdr{Id: dns.Id(), RecursionDesired: true}, |
74 | 74 |
Question: []dns.Question{{"www.google.com.", dns.TypeA, dns.ClassINET}}, |
75 | 75 |
} |
76 |
- in, err = dns.Exchange(m1, server) |
|
76 |
+ in, err = dns.Exchange(m1, masterConfig.DNSConfig.BindAddress) |
|
77 | 77 |
if err != nil { |
78 | 78 |
t.Fatalf("unexpected error: %v", err) |
79 | 79 |
} |
... | ... |
@@ -20,12 +20,12 @@ func init() { |
20 | 20 |
} |
21 | 21 |
|
22 | 22 |
func TestLogin(t *testing.T) { |
23 |
- startConfig, err := StartTestMaster() |
|
23 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
24 | 24 |
if err != nil { |
25 | 25 |
t.Fatalf("unexpected error: %v", err) |
26 | 26 |
} |
27 | 27 |
|
28 |
- openshiftClient, openshiftClientConfig, err := startConfig.GetOpenshiftClient() |
|
28 |
+ clusterAdminClient, _, clusterAdminClientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
29 | 29 |
if err != nil { |
30 | 30 |
t.Fatalf("unexpected error: %v", err) |
31 | 31 |
} |
... | ... |
@@ -40,7 +40,7 @@ func TestLogin(t *testing.T) { |
40 | 40 |
username := "joe" |
41 | 41 |
password := "pass" |
42 | 42 |
project := "the-singularity-is-near" |
43 |
- server := openshiftClientConfig.Host |
|
43 |
+ server := clusterAdminClientConfig.Host |
|
44 | 44 |
|
45 | 45 |
loginOptions = newLoginOptions(server, username, password, "", true) |
46 | 46 |
|
... | ... |
@@ -61,7 +61,7 @@ func TestLogin(t *testing.T) { |
61 | 61 |
} |
62 | 62 |
|
63 | 63 |
newProjectOptions := &newproject.NewProjectOptions{ |
64 |
- Client: openshiftClient, |
|
64 |
+ Client: clusterAdminClient, |
|
65 | 65 |
ProjectName: project, |
66 | 66 |
AdminRole: "admin", |
67 | 67 |
MasterPolicyNamespace: "master", |
... | ... |
@@ -25,13 +25,14 @@ func TestHTPasswd(t *testing.T) { |
25 | 25 |
os.Setenv("OPENSHIFT_OAUTH_PASSWORD_AUTH", "htpasswd") |
26 | 26 |
os.Setenv("OPENSHIFT_OAUTH_HTPASSWD_FILE", htpasswdFile.Name()) |
27 | 27 |
|
28 |
- startConfig, err := StartTestMaster() |
|
28 |
+ _, clusterAdminKubeConfig, err := StartTestMaster() |
|
29 | 29 |
if err != nil { |
30 | 30 |
t.Fatalf("unexpected error: %v", err) |
31 | 31 |
} |
32 |
- _, clientConfig, err := startConfig.GetOpenshiftClient() |
|
32 |
+ |
|
33 |
+ _, _, clientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
33 | 34 |
if err != nil { |
34 |
- t.Fatalf("unexpected error: %v", err) |
|
35 |
+ t.Errorf("unexpected error: %v", err) |
|
35 | 36 |
} |
36 | 37 |
|
37 | 38 |
// Use the server and CA info |
... | ... |
@@ -104,11 +104,12 @@ func TestOAuthRequestHeader(t *testing.T) { |
104 | 104 |
os.Setenv("OPENSHIFT_OAUTH_REQUEST_HEADER_CA_FILE", caFile.Name()) |
105 | 105 |
|
106 | 106 |
// Start server |
107 |
- startConfig, err := StartTestMaster() |
|
107 |
+ _, clusterAdminKubeConfig, err := StartTestAllInOne() |
|
108 | 108 |
if err != nil { |
109 | 109 |
t.Fatalf("unexpected error: %v", err) |
110 | 110 |
} |
111 |
- _, clientConfig, err := startConfig.GetOpenshiftClient() |
|
111 |
+ |
|
112 |
+ _, _, clientConfig, err := GetClusterAdminClient(clusterAdminKubeConfig) |
|
112 | 113 |
if err != nil { |
113 | 114 |
t.Fatalf("unexpected error: %v", err) |
114 | 115 |
} |
... | ... |
@@ -11,10 +11,12 @@ import ( |
11 | 11 |
|
12 | 12 |
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" |
13 | 13 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" |
14 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
|
14 | 15 |
|
15 | 16 |
"github.com/openshift/origin/pkg/client" |
16 | 17 |
newproject "github.com/openshift/origin/pkg/cmd/experimental/project" |
17 |
- start "github.com/openshift/origin/pkg/cmd/server" |
|
18 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
19 |
+ "github.com/openshift/origin/pkg/cmd/server/start" |
|
18 | 20 |
cmdutil "github.com/openshift/origin/pkg/cmd/util" |
19 | 21 |
"github.com/openshift/origin/pkg/cmd/util/tokencmd" |
20 | 22 |
) |
... | ... |
@@ -23,53 +25,71 @@ func init() { |
23 | 23 |
requireEtcd() |
24 | 24 |
} |
25 | 25 |
|
26 |
-func StartTestServer(args ...string) (start.Config, error) { |
|
27 |
- deleteAllEtcdKeys() |
|
28 |
- |
|
29 |
- startConfig := start.NewDefaultConfig() |
|
30 |
- startConfig.DNSBindAddr.DefaultPort = 8053 |
|
31 |
- startConfig.DNSBindAddr = startConfig.DNSBindAddr.Default() |
|
26 |
+func setupStartOptions() (*start.MasterArgs, *start.NodeArgs, *start.BindAddrArg, *start.ImageFormatArgs, *start.KubeConnectionArgs, *start.CertArgs) { |
|
27 |
+ masterArgs, nodeArgs, bindAddrArg, imageFormatArgs, kubeConnectionArgs, certArgs := start.GetAllInOneArgs() |
|
32 | 28 |
|
33 | 29 |
basedir := path.Join(os.TempDir(), "openshift-integration-tests") |
34 |
- |
|
35 |
- startConfig.VolumeDir = path.Join(basedir, "volume") |
|
36 |
- startConfig.EtcdDir = path.Join(basedir, "etcd") |
|
37 |
- startConfig.CertDir = path.Join(basedir, "cert") |
|
30 |
+ nodeArgs.VolumeDir = path.Join(basedir, "volume") |
|
31 |
+ masterArgs.EtcdDir = path.Join(basedir, "etcd") |
|
32 |
+ certArgs.CertDir = path.Join(basedir, "cert") |
|
38 | 33 |
|
39 | 34 |
// don't wait for nodes to come up |
40 |
- if len(args) > 0 && args[0] == "master" { |
|
41 |
- startConfig.NodeList = nil |
|
42 |
- } |
|
43 | 35 |
|
44 | 36 |
masterAddr := httptest.NewUnstartedServer(nil).Listener.Addr().String() |
45 | 37 |
fmt.Printf("masterAddr: %#v\n", masterAddr) |
46 |
- startConfig.MasterAddr.Set(masterAddr) |
|
47 |
- startConfig.BindAddr.Set(masterAddr) |
|
48 |
- startConfig.EtcdAddr.Set(getEtcdURL()) |
|
38 |
+ masterArgs.MasterAddr.Set(masterAddr) |
|
39 |
+ bindAddrArg.BindAddr.Set(masterAddr) |
|
40 |
+ masterArgs.EtcdAddr.Set(getEtcdURL()) |
|
49 | 41 |
|
50 | 42 |
assetAddr := httptest.NewUnstartedServer(nil).Listener.Addr().String() |
51 | 43 |
fmt.Printf("assetAddr: %#v\n", assetAddr) |
52 |
- startConfig.AssetBindAddr.Set(assetAddr) |
|
53 |
- startConfig.AssetPublicAddr.Set(assetAddr) |
|
44 |
+ masterArgs.AssetBindAddr.Set(assetAddr) |
|
45 |
+ masterArgs.AssetPublicAddr.Set(assetAddr) |
|
46 |
+ |
|
47 |
+ dnsAddr := httptest.NewUnstartedServer(nil).Listener.Addr().String() |
|
48 |
+ fmt.Printf("dnsAddr: %#v\n", dnsAddr) |
|
49 |
+ masterArgs.DNSBindAddr.Set(dnsAddr) |
|
50 |
+ |
|
51 |
+ return masterArgs, nodeArgs, bindAddrArg, imageFormatArgs, kubeConnectionArgs, certArgs |
|
52 |
+} |
|
53 |
+ |
|
54 |
+func getAdminKubeConfigFile(certArgs start.CertArgs) string { |
|
55 |
+ return path.Clean(path.Join(certArgs.CertDir, "admin/.kubeconfig")) |
|
56 |
+} |
|
57 |
+ |
|
58 |
+func StartTestAllInOne() (*configapi.MasterConfig, string, error) { |
|
59 |
+ deleteAllEtcdKeys() |
|
60 |
+ |
|
61 |
+ masterArgs, nodeArgs, _, _, _, _ := setupStartOptions() |
|
62 |
+ masterArgs.NodeList = nil |
|
54 | 63 |
|
55 |
- startConfig.Complete(args) |
|
64 |
+ startOptions := start.AllInOneOptions{} |
|
65 |
+ startOptions.MasterArgs, startOptions.NodeArgs = masterArgs, nodeArgs |
|
66 |
+ startOptions.Complete() |
|
56 | 67 |
|
57 | 68 |
errCh := make(chan error) |
58 | 69 |
go func() { |
59 |
- errCh <- startConfig.Start(args) |
|
70 |
+ errCh <- startOptions.StartAllInOne() |
|
60 | 71 |
close(errCh) |
61 | 72 |
}() |
62 | 73 |
|
74 |
+ adminKubeConfigFile := getAdminKubeConfigFile(*masterArgs.CertArgs) |
|
75 |
+ |
|
76 |
+ openshiftMasterConfig, err := startOptions.MasterArgs.BuildSerializeableMasterConfig() |
|
77 |
+ if err != nil { |
|
78 |
+ return nil, "", err |
|
79 |
+ } |
|
80 |
+ |
|
63 | 81 |
// wait for the server to come up: 35 seconds |
64 |
- if err := cmdutil.WaitForSuccessfulDial(true, "tcp", masterAddr, 100*time.Millisecond, 1*time.Second, 35); err != nil { |
|
82 |
+ if err := cmdutil.WaitForSuccessfulDial(true, "tcp", masterArgs.MasterAddr.URL.Host, 100*time.Millisecond, 1*time.Second, 35); err != nil { |
|
65 | 83 |
select { |
66 | 84 |
case err := <-errCh: |
67 | 85 |
if err != nil { |
68 |
- return *startConfig, err |
|
86 |
+ return nil, "", err |
|
69 | 87 |
} |
70 | 88 |
default: |
71 | 89 |
} |
72 |
- return *startConfig, err |
|
90 |
+ return nil, "", err |
|
73 | 91 |
} |
74 | 92 |
|
75 | 93 |
// try to get a client |
... | ... |
@@ -77,34 +97,74 @@ func StartTestServer(args ...string) (start.Config, error) { |
77 | 77 |
select { |
78 | 78 |
case err := <-errCh: |
79 | 79 |
if err != nil { |
80 |
- return *startConfig, err |
|
80 |
+ return nil, "", err |
|
81 | 81 |
} |
82 | 82 |
default: |
83 | 83 |
} |
84 | 84 |
// confirm that we can actually query from the api server |
85 |
- if client, _, err := startConfig.GetOpenshiftClient(); err == nil { |
|
85 |
+ |
|
86 |
+ if client, _, _, err := GetClusterAdminClient(adminKubeConfigFile); err == nil { |
|
86 | 87 |
if _, err := client.Policies("master").List(labels.Everything(), labels.Everything()); err == nil { |
87 | 88 |
break |
88 | 89 |
} |
89 | 90 |
} |
90 | 91 |
time.Sleep(100 * time.Millisecond) |
91 | 92 |
} |
92 |
- return *startConfig, nil |
|
93 |
+ return openshiftMasterConfig, adminKubeConfigFile, nil |
|
93 | 94 |
} |
94 | 95 |
|
95 |
-// StartTestMaster starts up a test master and returns back the startConfig so you can get clients and certs |
|
96 |
-func StartTestMaster() (start.Config, error) { |
|
97 |
- return StartTestServer("master") |
|
98 |
-} |
|
96 |
+// TODO Unify with StartAllInOne. |
|
99 | 97 |
|
100 |
-// StartTestNode starts up a test node and returns back the startConfig so you can get clients and certs |
|
101 |
-func StartTestNode() (start.Config, error) { |
|
102 |
- return StartTestServer("node") |
|
103 |
-} |
|
98 |
+// StartTestMaster starts up a test master and returns back the startOptions so you can get clients and certs |
|
99 |
+func StartTestMaster() (*configapi.MasterConfig, string, error) { |
|
100 |
+ deleteAllEtcdKeys() |
|
101 |
+ |
|
102 |
+ masterArgs, _, _, _, _, _ := setupStartOptions() |
|
103 |
+ |
|
104 |
+ startOptions := start.MasterOptions{} |
|
105 |
+ startOptions.MasterArgs = masterArgs |
|
106 |
+ startOptions.Complete() |
|
107 |
+ |
|
108 |
+ var startError error |
|
109 |
+ go func() { |
|
110 |
+ err := startOptions.StartMaster() |
|
111 |
+ if err != nil { |
|
112 |
+ startError = err |
|
113 |
+ fmt.Printf("ERROR STARTING SERVER! %v", err) |
|
114 |
+ } |
|
115 |
+ }() |
|
116 |
+ |
|
117 |
+ adminKubeConfigFile := getAdminKubeConfigFile(*masterArgs.CertArgs) |
|
118 |
+ |
|
119 |
+ openshiftMasterConfig, err := startOptions.MasterArgs.BuildSerializeableMasterConfig() |
|
120 |
+ if err != nil { |
|
121 |
+ return nil, "", err |
|
122 |
+ } |
|
123 |
+ |
|
124 |
+ // wait for the server to come up: 35 seconds |
|
125 |
+ if err := cmdutil.WaitForSuccessfulDial(true, "tcp", masterArgs.MasterAddr.URL.Host, 100*time.Millisecond, 1*time.Second, 35); err != nil { |
|
126 |
+ return nil, "", err |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ stopChannel := make(chan struct{}) |
|
130 |
+ util.Until( |
|
131 |
+ func() { |
|
132 |
+ if startError != nil { |
|
133 |
+ close(stopChannel) |
|
134 |
+ return |
|
135 |
+ } |
|
136 |
+ |
|
137 |
+ // confirm that we can actually query from the api server |
|
138 |
+ client, _, _, err := GetClusterAdminClient(adminKubeConfigFile) |
|
139 |
+ if err != nil { |
|
140 |
+ return |
|
141 |
+ } |
|
142 |
+ if _, err := client.Policies("master").List(labels.Everything(), labels.Everything()); err == nil { |
|
143 |
+ close(stopChannel) |
|
144 |
+ } |
|
145 |
+ }, 100*time.Millisecond, stopChannel) |
|
104 | 146 |
|
105 |
-// StartTestAllInOne starts up a test all-in-one and returns back the startConfig so you can get clients and certs |
|
106 |
-func StartTestAllInOne() (start.Config, error) { |
|
107 |
- return StartTestServer() |
|
147 |
+ return openshiftMasterConfig, adminKubeConfigFile, startError |
|
108 | 148 |
} |
109 | 149 |
|
110 | 150 |
// CreateNewProject creates a new project using the clusterAdminClient, then gets a token for the adminUser and returns |
... | ... |
@@ -144,3 +204,17 @@ func CreateNewProject(clusterAdminClient *client.Client, clientConfig kclient.Co |
144 | 144 |
|
145 | 145 |
return adminClient, nil |
146 | 146 |
} |
147 |
+ |
|
148 |
+func GetClusterAdminClient(adminKubeConfigFile string) (*client.Client, *kclient.Client, *kclient.Config, error) { |
|
149 |
+ kclient, clientConfig, err := configapi.GetKubeClient(adminKubeConfigFile) |
|
150 |
+ if err != nil { |
|
151 |
+ return nil, nil, nil, err |
|
152 |
+ } |
|
153 |
+ |
|
154 |
+ osclient, err := client.New(clientConfig) |
|
155 |
+ if err != nil { |
|
156 |
+ return nil, nil, nil, err |
|
157 |
+ } |
|
158 |
+ |
|
159 |
+ return osclient, kclient, clientConfig, nil |
|
160 |
+} |