-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
cmd.go
159 lines (138 loc) · 5.53 KB
/
cmd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package openshift_kube_apiserver
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"github.com/spf13/cobra"
"k8s.io/klog"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/util/templates"
configv1 "github.com/openshift/api/config/v1"
kubecontrolplanev1 "github.com/openshift/api/kubecontrolplane/v1"
legacyconfigv1 "github.com/openshift/api/legacyconfig/v1"
osinv1 "github.com/openshift/api/osin/v1"
"github.com/openshift/library-go/pkg/config/helpers"
"github.com/openshift/library-go/pkg/serviceability"
"github.com/openshift/origin/pkg/cmd/openshift-kube-apiserver/configdefault"
configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
configapilatest "github.com/openshift/origin/pkg/cmd/server/apis/config/latest"
"github.com/openshift/origin/pkg/cmd/server/apis/config/validation"
"github.com/openshift/origin/pkg/configconversion"
)
const RecommendedStartAPIServerName = "openshift-kube-apiserver"
type OpenShiftKubeAPIServerServer struct {
ConfigFile string
Output io.Writer
}
var longDescription = templates.LongDesc(`
Start the extended kube-apiserver with OpenShift security extensions`)
func NewOpenShiftKubeAPIServerServerCommand(name, basename string, out, errout io.Writer, stopCh <-chan struct{}) *cobra.Command {
options := &OpenShiftKubeAPIServerServer{Output: out}
cmd := &cobra.Command{
Use: name,
Short: "Start the OpenShift kube-apiserver",
Long: longDescription,
Run: func(c *cobra.Command, args []string) {
rest.CommandNameOverride = name
if err := options.Validate(); err != nil {
klog.Fatal(err)
}
serviceability.StartProfiler()
if err := options.RunAPIServer(stopCh); err != nil {
if kerrors.IsInvalid(err) {
if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil {
fmt.Fprintf(errout, "Invalid %s %s\n", details.Kind, details.Name)
for _, cause := range details.Causes {
fmt.Fprintf(errout, " %s: %s\n", cause.Field, cause.Message)
}
os.Exit(255)
}
}
klog.Fatal(err)
}
// When no error is returned, always return with zero exit code.
// This is here to make sure the container that run apiserver won't get accidentally restarted
// when the pod runs with restart on failure.
},
}
flags := cmd.Flags()
// This command only supports reading from config
flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from.")
cmd.MarkFlagFilename("config", "yaml", "yml")
cmd.MarkFlagRequired("config")
return cmd
}
func (o *OpenShiftKubeAPIServerServer) Validate() error {
if len(o.ConfigFile) == 0 {
return errors.New("--config is required for this command")
}
return nil
}
// RunAPIServer takes the options, starts the API server and runs until stopCh is closed or the initial listening fails
func (o *OpenShiftKubeAPIServerServer) RunAPIServer(stopCh <-chan struct{}) error {
// try to decode into our new types first. right now there is no validation, no file path resolution. this unsticks the operator to start.
// TODO add those things
configContent, err := ioutil.ReadFile(o.ConfigFile)
if err != nil {
return err
}
scheme := runtime.NewScheme()
utilruntime.Must(kubecontrolplanev1.Install(scheme))
codecs := serializer.NewCodecFactory(scheme)
obj, err := runtime.Decode(codecs.UniversalDecoder(kubecontrolplanev1.GroupVersion, configv1.GroupVersion, osinv1.GroupVersion), configContent)
switch {
case runtime.IsMissingVersion(err): // fall through to legacy master config
case runtime.IsMissingKind(err): // fall through to legacy master config
case runtime.IsNotRegisteredError(err): // fall through to legacy master config
case err != nil:
return err
case err == nil:
// Resolve relative to CWD
absoluteConfigFile, err := api.MakeAbs(o.ConfigFile, "")
if err != nil {
return err
}
configFileLocation := path.Dir(absoluteConfigFile)
config := obj.(*kubecontrolplanev1.KubeAPIServerConfig)
if err := helpers.ResolvePaths(configconversion.GetKubeAPIServerConfigFileReferences(config), configFileLocation); err != nil {
return err
}
configdefault.SetRecommendedKubeAPIServerConfigDefaults(config)
configdefault.ResolveDirectoriesForSATokenVerification(config)
return RunOpenShiftKubeAPIServerServer(config, stopCh)
}
// TODO this code disappears once the kube-core operator switches to external types
// TODO we will simply run some defaulting code and convert
// reading internal gives us defaulting that we need for now
masterConfig, err := configapilatest.ReadAndResolveMasterConfig(o.ConfigFile)
if err != nil {
return err
}
validationResults := validation.ValidateMasterConfig(masterConfig, nil)
if len(validationResults.Warnings) != 0 {
for _, warning := range validationResults.Warnings {
klog.Warningf("%v", warning)
}
}
if len(validationResults.Errors) != 0 {
return kerrors.NewInvalid(configapi.Kind("MasterConfig"), "master-config.yaml", validationResults.Errors)
}
// round trip to external
externalMasterConfig, err := configapi.Scheme.ConvertToVersion(masterConfig, legacyconfigv1.LegacySchemeGroupVersion)
if err != nil {
return err
}
kubeAPIServerConfig, err := configconversion.ConvertMasterConfigToKubeAPIServerConfig(externalMasterConfig.(*legacyconfigv1.MasterConfig))
if err != nil {
return err
}
return RunOpenShiftKubeAPIServerServer(kubeAPIServerConfig, stopCh)
}