// Visit implements Visitor over a stream. StreamVisitor is able to distinct multiple resources in one stream. func (v *StreamVisitor) Visit(fn VisitorFunc) error { d := yaml.NewYAMLOrJSONDecoder(v.Reader, 4096) for { ext := runtime.RawExtension{} if err := d.Decode(&ext); err != nil { if err == io.EOF { return nil } return err } // TODO: This needs to be able to handle object in other encodings and schemas. ext.Raw = bytes.TrimSpace(ext.Raw) if len(ext.Raw) == 0 || bytes.Equal(ext.Raw, []byte("null")) { continue } if err := ValidateSchema(ext.Raw, v.Schema); err != nil { return fmt.Errorf("error validating %q: %v", v.Source, err) } info, err := v.InfoForData(ext.Raw, v.Source) if err != nil { if fnErr := fn(info, err); fnErr != nil { return fnErr } continue } if err := fn(info, nil); err != nil { return err } } }
// NewImagePolicyWebhook a new imagePolicyWebhook from the provided config file. // The config file is specified by --admission-controller-config-file and has the // following format for a webhook: // // { // "imagePolicy": { // "kubeConfigFile": "path/to/kubeconfig/for/backend", // "allowTTL": 30, # time in s to cache approval // "denyTTL": 30, # time in s to cache denial // "retryBackoff": 500, # time in ms to wait between retries // "defaultAllow": true # determines behavior if the webhook backend fails // } // } // // The config file may be json or yaml. // // The kubeconfig property refers to another file in the kubeconfig format which // specifies how to connect to the webhook backend. // // The kubeconfig's cluster field is used to refer to the remote service, user refers to the returned authorizer. // // # clusters refers to the remote service. // clusters: // - name: name-of-remote-imagepolicy-service // cluster: // certificate-authority: /path/to/ca.pem # CA for verifying the remote service. // server: https://images.example.com/policy # URL of remote service to query. Must use 'https'. // // # users refers to the API server's webhook configuration. // users: // - name: name-of-api-server // user: // client-certificate: /path/to/cert.pem # cert for the webhook plugin to use // client-key: /path/to/key.pem # key matching the cert // // For additional HTTP configuration, refer to the kubeconfig documentation // http://kubernetes.io/v1.1/docs/user-guide/kubeconfig-file.html. func NewImagePolicyWebhook(configFile io.Reader) (admission.Interface, error) { // TODO: move this to a versioned configuration file format var config AdmissionConfig d := yaml.NewYAMLOrJSONDecoder(configFile, 4096) err := d.Decode(&config) if err != nil { return nil, err } whConfig := config.ImagePolicyWebhook if err := normalizeWebhookConfig(&whConfig); err != nil { return nil, err } gw, err := webhook.NewGenericWebhook(whConfig.KubeConfigFile, groupVersions, whConfig.RetryBackoff) if err != nil { return nil, err } return &imagePolicyWebhook{ Handler: admission.NewHandler(admission.Create, admission.Update), webhook: gw, responseCache: cache.NewLRUExpireCache(1024), allowTTL: whConfig.AllowTTL, denyTTL: whConfig.DenyTTL, defaultAllow: whConfig.DefaultAllow, }, nil }
// readConfig reads default value of clusterDefaultNodeSelector // from the file provided with --admission-control-config-file // If the file is not supplied, it defaults to "" // The format in a file: // podNodeSelectorPluginConfig: // clusterDefaultNodeSelector: <node-selectors-labels> // namespace1: <node-selectors-labels> // namespace2: <node-selectors-labels> func readConfig(config io.Reader) *pluginConfig { defaultConfig := &pluginConfig{} if config == nil || reflect.ValueOf(config).IsNil() { return defaultConfig } d := yaml.NewYAMLOrJSONDecoder(config, 4096) for { if err := d.Decode(defaultConfig); err != nil { if err != io.EOF { continue } } break } return defaultConfig }