Skip to content

Commit 35aff64

Browse files
committed
Admission refactor.
Signed-off-by: Klaus Ma <klaus1982.cn@gmail.com>
1 parent cbe3c00 commit 35aff64

File tree

17 files changed

+572
-488
lines changed

17 files changed

+572
-488
lines changed

cmd/admission/app/options/options.go

Lines changed: 17 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ import (
2020
"fmt"
2121

2222
"github.com/spf13/pflag"
23-
24-
"k8s.io/api/admissionregistration/v1beta1"
25-
apierrors "k8s.io/apimachinery/pkg/api/errors"
26-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27-
"k8s.io/client-go/kubernetes"
28-
admissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1"
29-
"k8s.io/klog"
3023
)
3124

3225
const (
@@ -35,20 +28,17 @@ const (
3528

3629
// Config admission-controller server config.
3730
type Config struct {
38-
Master string
39-
Kubeconfig string
40-
CertFile string
41-
KeyFile string
42-
CaCertFile string
43-
Port int
44-
MutateWebhookConfigName string
45-
MutateWebhookName string
46-
ValidateWebhookConfigName string
47-
ValidateWebhookName string
48-
PrintVersion bool
49-
AdmissionServiceName string
50-
AdmissionServiceNamespace string
51-
SchedulerName string
31+
Master string
32+
Kubeconfig string
33+
CertFile string
34+
KeyFile string
35+
CaCertFile string
36+
Port int
37+
PrintVersion bool
38+
WebhookName string
39+
WebhookNamespace string
40+
SchedulerName string
41+
WebhookURL string
5242
}
5343

5444
// NewConfig create new config
@@ -65,210 +55,21 @@ func (c *Config) AddFlags(fs *pflag.FlagSet) {
6555
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
6656
"after server cert).")
6757
fs.StringVar(&c.KeyFile, "tls-private-key-file", c.KeyFile, "File containing the default x509 private key matching --tls-cert-file.")
68-
fs.StringVar(&c.CaCertFile, "ca-cert-file", c.CaCertFile, "File containing the x509 Certificate for HTTPS.")
6958
fs.IntVar(&c.Port, "port", 443, "the port used by admission-controller-server.")
70-
fs.StringVar(&c.MutateWebhookConfigName, "mutate-webhook-config-name", "",
71-
"Name of the mutatingwebhookconfiguration resource in Kubernetes [Deprecated]: it will be generated when not specified.")
72-
fs.StringVar(&c.MutateWebhookName, "mutate-webhook-name", "",
73-
"Name of the webhook entry in the webhook config. [Deprecated]: it will be generated when not specified")
74-
fs.StringVar(&c.ValidateWebhookConfigName, "validate-webhook-config-name", "",
75-
"Name of the mutatingwebhookconfiguration resource in Kubernetes. [Deprecated]: it will be generated when not specified")
76-
fs.StringVar(&c.ValidateWebhookName, "validate-webhook-name", "",
77-
"Name of the webhook entry in the webhook config. [Deprecated]: it will be generated when not specified")
7859
fs.BoolVar(&c.PrintVersion, "version", false, "Show version and quit")
79-
fs.StringVar(&c.AdmissionServiceNamespace, "webhook-namespace", "default", "The namespace of this webhook")
80-
fs.StringVar(&c.AdmissionServiceName, "webhook-service-name", "admission-service", "The name of this admission service")
60+
61+
fs.StringVar(&c.CaCertFile, "ca-cert-file", c.CaCertFile, "File containing the x509 Certificate for HTTPS.")
62+
fs.StringVar(&c.WebhookNamespace, "webhook-namespace", "", "The namespace of this webhook")
63+
fs.StringVar(&c.WebhookName, "webhook-service-name", "", "The name of this webhook")
64+
fs.StringVar(&c.WebhookURL, "webhook-url", "", "The url of this webhook")
65+
8166
fs.StringVar(&c.SchedulerName, "scheduler-name", defaultSchedulerName, "Volcano will handle pods whose .spec.SchedulerName is same as scheduler-name")
8267
}
8368

84-
const (
85-
// ValidateConfigName ValidatingWebhookConfiguration name format
86-
ValidateConfigName = "%s-validate-job"
87-
// MutateConfigName MutatingWebhookConfiguration name format
88-
MutateConfigName = "%s-mutate-job"
89-
// ValidateHookName Default name for webhooks in ValidatingWebhookConfiguration
90-
ValidateHookName = "validatejob.volcano.sh"
91-
// MutateHookName Default name for webhooks in MutatingWebhookConfiguration
92-
MutateHookName = "mutatejob.volcano.sh"
93-
// ValidatePodConfigName ValidatingWebhookPodConfiguration name format
94-
ValidatePodConfigName = "%s-validate-pod"
95-
// ValidatePodHookName Default name for webhooks in ValidatingWebhookPodConfiguration
96-
ValidatePodHookName = "validatepod.volcano.sh"
97-
)
98-
9969
// CheckPortOrDie check valid port range
10070
func (c *Config) CheckPortOrDie() error {
10171
if c.Port < 1 || c.Port > 65535 {
10272
return fmt.Errorf("the port should be in the range of 1 and 65535")
10373
}
10474
return nil
10575
}
106-
107-
func useGeneratedNameIfRequired(configured, generated string) string {
108-
if configured != "" {
109-
return configured
110-
}
111-
return generated
112-
}
113-
114-
// RegisterWebhooks register webhooks for admission service
115-
func RegisterWebhooks(c *Config, clienset *kubernetes.Clientset, cabundle []byte) error {
116-
ignorePolicy := v1beta1.Ignore
117-
118-
//Prepare validate webhooks
119-
path := "/jobs"
120-
JobValidateHooks := v1beta1.ValidatingWebhookConfiguration{
121-
ObjectMeta: metav1.ObjectMeta{
122-
Name: useGeneratedNameIfRequired(c.ValidateWebhookConfigName,
123-
fmt.Sprintf(ValidateConfigName, c.AdmissionServiceName)),
124-
},
125-
Webhooks: []v1beta1.Webhook{{
126-
Name: useGeneratedNameIfRequired(c.ValidateWebhookName, ValidateHookName),
127-
Rules: []v1beta1.RuleWithOperations{
128-
{
129-
Operations: []v1beta1.OperationType{v1beta1.Create, v1beta1.Update},
130-
Rule: v1beta1.Rule{
131-
APIGroups: []string{"batch.volcano.sh"},
132-
APIVersions: []string{"v1alpha1"},
133-
Resources: []string{"jobs"},
134-
},
135-
},
136-
},
137-
ClientConfig: v1beta1.WebhookClientConfig{
138-
Service: &v1beta1.ServiceReference{
139-
Name: c.AdmissionServiceName,
140-
Namespace: c.AdmissionServiceNamespace,
141-
Path: &path,
142-
},
143-
CABundle: cabundle,
144-
},
145-
FailurePolicy: &ignorePolicy,
146-
}},
147-
}
148-
149-
if err := registerValidateWebhook(clienset.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations(),
150-
[]v1beta1.ValidatingWebhookConfiguration{JobValidateHooks}); err != nil {
151-
return err
152-
}
153-
154-
//Prepare mutate jobs
155-
path = "/mutating-jobs"
156-
JobMutateHooks := v1beta1.MutatingWebhookConfiguration{
157-
ObjectMeta: metav1.ObjectMeta{
158-
Name: useGeneratedNameIfRequired(c.MutateWebhookConfigName,
159-
fmt.Sprintf(MutateConfigName, c.AdmissionServiceName)),
160-
},
161-
Webhooks: []v1beta1.Webhook{{
162-
Name: useGeneratedNameIfRequired(c.MutateWebhookName, MutateHookName),
163-
Rules: []v1beta1.RuleWithOperations{
164-
{
165-
Operations: []v1beta1.OperationType{v1beta1.Create},
166-
Rule: v1beta1.Rule{
167-
APIGroups: []string{"batch.volcano.sh"},
168-
APIVersions: []string{"v1alpha1"},
169-
Resources: []string{"jobs"},
170-
},
171-
},
172-
},
173-
ClientConfig: v1beta1.WebhookClientConfig{
174-
Service: &v1beta1.ServiceReference{
175-
Name: c.AdmissionServiceName,
176-
Namespace: c.AdmissionServiceNamespace,
177-
Path: &path,
178-
},
179-
CABundle: cabundle,
180-
},
181-
FailurePolicy: &ignorePolicy,
182-
}},
183-
}
184-
185-
if err := registerMutateWebhook(clienset.AdmissionregistrationV1beta1().MutatingWebhookConfigurations(),
186-
[]v1beta1.MutatingWebhookConfiguration{JobMutateHooks}); err != nil {
187-
return err
188-
}
189-
190-
// Prepare validate pods
191-
path = "/pods"
192-
PodValidateHooks := v1beta1.ValidatingWebhookConfiguration{
193-
ObjectMeta: metav1.ObjectMeta{
194-
Name: useGeneratedNameIfRequired("",
195-
fmt.Sprintf(ValidatePodConfigName, c.AdmissionServiceName)),
196-
},
197-
Webhooks: []v1beta1.Webhook{{
198-
Name: useGeneratedNameIfRequired("", ValidatePodHookName),
199-
Rules: []v1beta1.RuleWithOperations{
200-
{
201-
Operations: []v1beta1.OperationType{v1beta1.Create},
202-
Rule: v1beta1.Rule{
203-
APIGroups: []string{""},
204-
APIVersions: []string{"v1"},
205-
Resources: []string{"pods"},
206-
},
207-
},
208-
},
209-
ClientConfig: v1beta1.WebhookClientConfig{
210-
Service: &v1beta1.ServiceReference{
211-
Name: c.AdmissionServiceName,
212-
Namespace: c.AdmissionServiceNamespace,
213-
Path: &path,
214-
},
215-
CABundle: cabundle,
216-
},
217-
FailurePolicy: &ignorePolicy,
218-
}},
219-
}
220-
221-
if err := registerValidateWebhook(clienset.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations(),
222-
[]v1beta1.ValidatingWebhookConfiguration{PodValidateHooks}); err != nil {
223-
return err
224-
}
225-
226-
return nil
227-
228-
}
229-
230-
func registerMutateWebhook(client admissionregistrationv1beta1.MutatingWebhookConfigurationInterface,
231-
webhooks []v1beta1.MutatingWebhookConfiguration) error {
232-
for _, hook := range webhooks {
233-
existing, err := client.Get(hook.Name, metav1.GetOptions{})
234-
if err != nil && !apierrors.IsNotFound(err) {
235-
return err
236-
}
237-
if err == nil && existing != nil {
238-
klog.Infof("Updating MutatingWebhookConfiguration %v", hook)
239-
existing.Webhooks = hook.Webhooks
240-
if _, err := client.Update(existing); err != nil {
241-
return err
242-
}
243-
} else {
244-
klog.Infof("Creating MutatingWebhookConfiguration %v", hook)
245-
if _, err := client.Create(&hook); err != nil {
246-
return err
247-
}
248-
}
249-
}
250-
return nil
251-
}
252-
253-
func registerValidateWebhook(client admissionregistrationv1beta1.ValidatingWebhookConfigurationInterface,
254-
webhooks []v1beta1.ValidatingWebhookConfiguration) error {
255-
for _, hook := range webhooks {
256-
existing, err := client.Get(hook.Name, metav1.GetOptions{})
257-
if err != nil && !apierrors.IsNotFound(err) {
258-
return err
259-
}
260-
if err == nil && existing != nil {
261-
existing.Webhooks = hook.Webhooks
262-
klog.Infof("Updating ValidatingWebhookConfiguration %v", hook)
263-
if _, err := client.Update(existing); err != nil {
264-
return err
265-
}
266-
} else {
267-
klog.Infof("Creating ValidatingWebhookConfiguration %v", hook)
268-
if _, err := client.Create(&hook); err != nil {
269-
return err
270-
}
271-
}
272-
}
273-
return nil
274-
}

cmd/admission/app/server.go

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,60 +17,83 @@ limitations under the License.
1717
package app
1818

1919
import (
20-
"crypto/tls"
20+
"fmt"
21+
"io/ioutil"
22+
"net/http"
23+
"os"
24+
"os/signal"
25+
"strconv"
26+
"syscall"
2127

22-
"k8s.io/client-go/kubernetes"
23-
"k8s.io/client-go/rest"
28+
"k8s.io/client-go/tools/clientcmd"
2429
"k8s.io/klog"
2530

2631
"volcano.sh/volcano/cmd/admission/app/options"
27-
"volcano.sh/volcano/pkg/client/clientset/versioned"
32+
"volcano.sh/volcano/pkg/admission/router"
33+
"volcano.sh/volcano/pkg/version"
2834
)
2935

30-
// GetClient Get a clientset with restConfig.
31-
func GetClient(restConfig *rest.Config) *kubernetes.Clientset {
32-
clientset, err := kubernetes.NewForConfig(restConfig)
36+
// Run start the service of admission controller.
37+
func Run(config *options.Config) error {
38+
if config.PrintVersion {
39+
version.PrintVersionAndExit()
40+
return nil
41+
}
42+
43+
if config.WebhookURL == "" && config.WebhookNamespace == "" && config.WebhookName == "" {
44+
return fmt.Errorf("failed to start webhooks as both 'url' and 'namespace/name' of webhook are empty")
45+
}
46+
47+
restConfig, err := clientcmd.BuildConfigFromFlags(config.Master, config.Kubeconfig)
3348
if err != nil {
34-
klog.Fatal(err)
49+
return fmt.Errorf("unable to build k8s config: %v", err)
3550
}
36-
return clientset
37-
}
3851

39-
// GetVolcanoClient get a clientset for volcano
40-
func GetVolcanoClient(restConfig *rest.Config) *versioned.Clientset {
41-
clientset, err := versioned.NewForConfig(restConfig)
52+
caBundle, err := ioutil.ReadFile(config.CaCertFile)
4253
if err != nil {
43-
klog.Fatal(err)
54+
return fmt.Errorf("unable to read cacert file (%s): %v", config.CaCertFile, err)
4455
}
45-
return clientset
46-
}
4756

48-
// ConfigTLS is a helper function that generate tls certificates from directly defined tls config or kubeconfig
49-
// These are passed in as command line for cluster certification. If tls config is passed in, we use the directly
50-
// defined tls config, else use that defined in kubeconfig
51-
func ConfigTLS(config *options.Config, restConfig *rest.Config) *tls.Config {
52-
if len(config.CertFile) != 0 && len(config.KeyFile) != 0 {
53-
sCert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile)
54-
if err != nil {
55-
klog.Fatal(err)
57+
vClient := getVolcanoClient(restConfig)
58+
kubeClient := getKubeClient(restConfig)
59+
router.ForEachAdmission(func(service *router.AdmissionService) {
60+
if service.Config != nil {
61+
service.Config.VolcanoClient = vClient
62+
service.Config.SchedulerName = config.SchedulerName
5663
}
5764

58-
return &tls.Config{
59-
Certificates: []tls.Certificate{sCert},
60-
}
61-
}
65+
klog.V(3).Infof("Registered '%s' as webhook.", service.Path)
66+
http.HandleFunc(service.Path, service.Handler)
67+
68+
klog.V(3).Infof("Registered configuration for webhook <%s>", service.Path)
69+
registerWebhookConfig(kubeClient, config, service, caBundle)
70+
})
71+
72+
webhookServeError := make(chan struct{})
73+
stopChannel := make(chan os.Signal)
74+
signal.Notify(stopChannel, syscall.SIGTERM, syscall.SIGINT)
6275

63-
if len(restConfig.CertData) != 0 && len(restConfig.KeyData) != 0 {
64-
sCert, err := tls.X509KeyPair(restConfig.CertData, restConfig.KeyData)
65-
if err != nil {
66-
klog.Fatal(err)
76+
server := &http.Server{
77+
Addr: ":" + strconv.Itoa(config.Port),
78+
TLSConfig: configTLS(config, restConfig),
79+
}
80+
go func() {
81+
err = server.ListenAndServeTLS("", "")
82+
if err != nil && err != http.ErrServerClosed {
83+
klog.Fatalf("ListenAndServeTLS for admission webhook failed: %v", err)
84+
close(webhookServeError)
6785
}
6886

69-
return &tls.Config{
70-
Certificates: []tls.Certificate{sCert},
87+
klog.Info("Volcano Webhook manager started.")
88+
}()
89+
90+
select {
91+
case <-stopChannel:
92+
if err := server.Close(); err != nil {
93+
return fmt.Errorf("close admission server failed: %v", err)
7194
}
95+
return nil
96+
case <-webhookServeError:
97+
return fmt.Errorf("unknown webhook server error")
7298
}
73-
74-
klog.Fatal("tls: failed to find any tls config data")
75-
return &tls.Config{}
7699
}

0 commit comments

Comments
 (0)