From 74fbac95f98c15d7f028120f7a6807e12130b806 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Wed, 30 May 2018 23:14:49 +0300 Subject: [PATCH 01/17] Move CRD resources under pkg/api --- pkg/api/types/v1/client.go | 28 +++++ pkg/api/types/v1/imagemapping.go | 152 +++++++++++++++++++++++ pkg/api/types/v1/register.go | 88 +++++++++++++ pkg/imagetranslation/crd_source.go | 144 +-------------------- pkg/imagetranslation/fake_source.go | 14 ++- pkg/imagetranslation/file_source.go | 6 +- pkg/imagetranslation/interface.go | 67 +--------- pkg/imagetranslation/translator.go | 7 +- pkg/imagetranslation/translator_test.go | 8 +- pkg/imagetranslation/transport_test.go | 67 +++++----- pkg/manager/manager.go | 3 +- tests/e2e/framework/controller.go | 10 +- tests/e2e/image_name_translation_test.go | 8 +- 13 files changed, 341 insertions(+), 261 deletions(-) create mode 100644 pkg/api/types/v1/client.go create mode 100644 pkg/api/types/v1/imagemapping.go create mode 100644 pkg/api/types/v1/register.go diff --git a/pkg/api/types/v1/client.go b/pkg/api/types/v1/client.go new file mode 100644 index 000000000..7ca6d2765 --- /dev/null +++ b/pkg/api/types/v1/client.go @@ -0,0 +1,28 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or ≈git-agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "k8s.io/client-go/rest" + + "github.com/Mirantis/virtlet/pkg/utils" +) + +// GetCRDRestClient returns ReST client that can be used to work with virtlet CRDs +func GetCRDRestClient(cfg *rest.Config) (*rest.RESTClient, error) { + return utils.GetK8sRestClient(cfg, scheme, &schemeGroupVersion) +} diff --git a/pkg/api/types/v1/imagemapping.go b/pkg/api/types/v1/imagemapping.go new file mode 100644 index 000000000..2a46c4729 --- /dev/null +++ b/pkg/api/types/v1/imagemapping.go @@ -0,0 +1,152 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or ≈git-agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// TranslationRule represents a single translation rule from either name or regexp to Endpoint +type TranslationRule struct { + // Name defines a mapping from a fixed name + Name string `yaml:"name,omitempty" json:"name,omitempty"` + + // Regex defines a mapping from all names that match this regexp. In this case replacements can be used for Endpoint.URL + Regex string `yaml:"regexp,omitempty" json:"regexp,omitempty"` + + // URL is the image URL + URL string `yaml:"url,omitempty" json:"url,omitempty"` + + // Transport is the optional transport profile name to be used for the downloading + Transport string `yaml:"transport,omitempty" json:"transport,omitempty"` +} + +// ImageTranslation is a single translation config with optional prefix name +type ImageTranslation struct { + // Prefix allows to have several config-sets and distinguish them by using `prefix/imageName` notation. Optional. + Prefix string `yaml:"prefix,omitempty" json:"prefix,omitempty"` + + // Rules is a list of translations + Rules []TranslationRule `yaml:"translations" json:"translations"` + + // Transports is a map of available transport profiles available for endpoints + Transports map[string]TransportProfile `yaml:"transports" json:"transports"` +} + +// TransportProfile contains all the http transport settings +type TransportProfile struct { + // MaxRedirects is the maximum number of redirects that downloader is allowed to follow. Default is 9 (download fails on request #10) + MaxRedirects *int `yaml:"maxRedirects,omitempty" json:"maxRedirects,omitempty"` + + // TLS config + TLS *TLSConfig `yaml:"tls,omitempty" json:"tls,omitempty"` + + // TimeoutMilliseconds specifies a time limit in milliseconds for http(s) download request. <= 0 is no timeout (default) + TimeoutMilliseconds int `yaml:"timeout,omitempty" json:"timeout,omitempty"` + + // Proxy server to use for downloading + Proxy string `yaml:"proxy,omitempty" json:"proxy,omitempty"` +} + +// TLSConfig has the TLS transport parameters +type TLSConfig struct { + // Certificates - TLS certificates to use for connection + Certificates []TLSCertificate `yaml:"certificates,omitempty" json:"certificates,omitempty"` + + // ServerName is used to verify the hostname on the returned certificates. Needed when url points to domain that + // differs from CN of certificate + ServerName string `yaml:"serverName,omitempty" json:"serverName,omitempty"` + + // Insecure is a flag to bypass server certificate validation + Insecure bool `yaml:"insecure,omitempty" json:"insecure,omitempty"` +} + +// TLSCertificate has the x509 certificate PEM data with optional PEM private key +type TLSCertificate struct { + // Cert certificate (PEM) block + Cert string `yaml:"cert,omitempty" json:"cert,omitempty"` + + // Key - keypair (PEM) block + Key string `yaml:"key,omitempty" json:"key,omitempty"` +} + +// VirtletImageMapping represents an ImageTranslation wrapped in k8s object +type VirtletImageMapping struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + Spec ImageTranslation `json:"spec"` +} + +// DeepCopyObject implements DeepCopyObject method of runtime.Object interface +func (vim *VirtletImageMapping) DeepCopyObject() runtime.Object { + if vim == nil { + return nil + } + r := *vim + if vim.Spec.Transports == nil { + return &r + } + + transportMap := make(map[string]TransportProfile) + for k, tr := range vim.Spec.Transports { + if tr.MaxRedirects != nil { + redirs := *tr.MaxRedirects + tr.MaxRedirects = &redirs + } + if tr.TLS != nil { + tls := *tr.TLS + tr.TLS = &tls + } + transportMap[k] = tr + } + return &r +} + +// Name implements TranslationConfig Name +func (vim *VirtletImageMapping) Name() string { + return vim.ObjectMeta.Name +} + +// Payload implements TranslationConfig Payload +func (vim *VirtletImageMapping) Payload() (ImageTranslation, error) { + return vim.Spec, nil +} + +// VirtletImageMappingList is a k8s representation of list of translation configs +type VirtletImageMappingList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata"` + Items []VirtletImageMapping `json:"items"` +} + +// DeepCopyObject implements DeepCopyObject method of runtime.Object interface +func (l *VirtletImageMappingList) DeepCopyObject() runtime.Object { + if l == nil { + return l + } + r := &VirtletImageMappingList{ + TypeMeta: l.TypeMeta, + ListMeta: l.ListMeta, + } + for _, vim := range l.Items { + r.Items = append(r.Items, *vim.DeepCopyObject().(*VirtletImageMapping)) + } + return r +} + +// TODO: update '... implements ...' comments in this file diff --git a/pkg/api/types/v1/register.go b/pkg/api/types/v1/register.go new file mode 100644 index 000000000..a1852a3fc --- /dev/null +++ b/pkg/api/types/v1/register.go @@ -0,0 +1,88 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + apierrors "k8s.io/apimachinery/pkg/api/errors" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/Mirantis/virtlet/pkg/utils" +) + +const ( + groupName = "virtlet.k8s" + version = "v1" +) + +var ( + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + scheme = runtime.NewScheme() + schemeGroupVersion = schema.GroupVersion{Group: groupName, Version: version} +) + +// RegisterCustomResourceTypes registers custom resource definition for VirtletImageMapping kind in k8s +func RegisterCustomResourceTypes() error { + crd := apiextensionsv1beta1.CustomResourceDefinition{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "virtletimagemappings." + groupName, + }, + Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ + Group: groupName, + Version: version, + Scope: apiextensionsv1beta1.NamespaceScoped, + Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ + Plural: "virtletimagemappings", + Singular: "virtletimagemapping", + Kind: "VirtletImageMapping", + ShortNames: []string{"vim"}, + }, + }, + } + cfg, err := utils.GetK8sClientConfig("") + if err != nil || cfg.Host == "" { + return err + } + extensionsClientSet, err := apiextensionsclient.NewForConfig(cfg) + if err != nil { + panic(err) + } + + _, err = extensionsClientSet.ApiextensionsV1beta1().CustomResourceDefinitions().Create(&crd) + if err == nil || apierrors.IsAlreadyExists(err) { + return nil + } + return err +} + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(schemeGroupVersion, + &VirtletImageMapping{}, + &VirtletImageMappingList{}, + ) + meta_v1.AddToGroupVersion(scheme, schemeGroupVersion) + return nil +} + +func init() { + if err := schemeBuilder.AddToScheme(scheme); err != nil { + panic(err) + } +} diff --git a/pkg/imagetranslation/crd_source.go b/pkg/imagetranslation/crd_source.go index 8d3eeb6c3..9937eabf8 100644 --- a/pkg/imagetranslation/crd_source.go +++ b/pkg/imagetranslation/crd_source.go @@ -20,141 +20,10 @@ import ( "context" "fmt" - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/rest" - + "github.com/Mirantis/virtlet/pkg/api/types/v1" "github.com/Mirantis/virtlet/pkg/utils" ) -const groupName = "virtlet.k8s" -const version = "v1" - -var ( - schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - scheme = runtime.NewScheme() - schemeGroupVersion = schema.GroupVersion{Group: groupName, Version: version} -) - -// VirtletImageMapping represents an ImageTranslation wrapped in k8s object -type VirtletImageMapping struct { - meta_v1.TypeMeta `json:",inline"` - meta_v1.ObjectMeta `json:"metadata"` - Spec ImageTranslation `json:"spec"` -} - -// DeepCopyObject implements DeepCopyObject method of runtime.Object interface -func (vim *VirtletImageMapping) DeepCopyObject() runtime.Object { - if vim == nil { - return nil - } - r := *vim - if vim.Spec.Transports == nil { - return &r - } - - transportMap := make(map[string]TransportProfile) - for k, tr := range vim.Spec.Transports { - if tr.MaxRedirects != nil { - redirs := *tr.MaxRedirects - tr.MaxRedirects = &redirs - } - if tr.TLS != nil { - tls := *tr.TLS - tr.TLS = &tls - } - transportMap[k] = tr - } - return &r -} - -var _ TranslationConfig = VirtletImageMapping{} - -// VirtletImageMappingList is a k8s representation of list of translation configs -type VirtletImageMappingList struct { - meta_v1.TypeMeta `json:",inline"` - meta_v1.ListMeta `json:"metadata"` - Items []VirtletImageMapping `json:"items"` -} - -// DeepCopyObject implements DeepCopyObject method of runtime.Object interface -func (l *VirtletImageMappingList) DeepCopyObject() runtime.Object { - if l == nil { - return l - } - r := &VirtletImageMappingList{ - TypeMeta: l.TypeMeta, - ListMeta: l.ListMeta, - } - for _, vim := range l.Items { - r.Items = append(r.Items, *vim.DeepCopyObject().(*VirtletImageMapping)) - } - return r -} - -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(schemeGroupVersion, - &VirtletImageMapping{}, - &VirtletImageMappingList{}, - ) - meta_v1.AddToGroupVersion(scheme, schemeGroupVersion) - return nil -} - -func init() { - if err := schemeBuilder.AddToScheme(scheme); err != nil { - panic(err) - } -} - -// RegisterCustomResourceType registers custom resource definition for VirtletImageMapping kind in k8s -func RegisterCustomResourceType() error { - crd := apiextensionsv1beta1.CustomResourceDefinition{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "virtletimagemappings." + groupName, - }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: groupName, - Version: version, - Scope: apiextensionsv1beta1.NamespaceScoped, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Plural: "virtletimagemappings", - Singular: "virtletimagemapping", - Kind: "VirtletImageMapping", - ShortNames: []string{"vim"}, - }, - }, - } - cfg, err := utils.GetK8sClientConfig("") - if err != nil || cfg.Host == "" { - return err - } - extensionsClientSet, err := apiextensionsclient.NewForConfig(cfg) - if err != nil { - panic(err) - } - - _, err = extensionsClientSet.ApiextensionsV1beta1().CustomResourceDefinitions().Create(&crd) - if err == nil || errors.IsAlreadyExists(err) { - return nil - } - return err -} - -// Name implements TranslationConfig Name -func (vim VirtletImageMapping) Name() string { - return vim.ObjectMeta.Name -} - -// Payload implements TranslationConfig Payload -func (vim VirtletImageMapping) Payload() (ImageTranslation, error) { - return vim.Spec, nil -} - type crdConfigSource struct { namespace string } @@ -172,11 +41,11 @@ func (cs crdConfigSource) Configs(ctx context.Context) ([]TranslationConfig, err return nil, nil } - client, err := GetCRDRestClient(cfg) + client, err := v1.GetCRDRestClient(cfg) if err != nil { return nil, err } - var list VirtletImageMappingList + var list v1.VirtletImageMappingList err = client.Get(). Context(ctx). Resource("virtletimagemappings"). @@ -187,17 +56,12 @@ func (cs crdConfigSource) Configs(ctx context.Context) ([]TranslationConfig, err } result := make([]TranslationConfig, len(list.Items)) for i, v := range list.Items { - result[i] = v + result[i] = &v } return result, nil } -// GetCRDRestClient returns ReST client that can be used to work with virtlet CRDs -func GetCRDRestClient(cfg *rest.Config) (*rest.RESTClient, error) { - return utils.GetK8sRestClient(cfg, scheme, &schemeGroupVersion) -} - // Description implements ConfigSource Description func (cs crdConfigSource) Description() string { return fmt.Sprintf("Kubernetes VirtletImageMapping resources in namespace %q", cs.namespace) diff --git a/pkg/imagetranslation/fake_source.go b/pkg/imagetranslation/fake_source.go index ee762f743..3a2bdfc21 100644 --- a/pkg/imagetranslation/fake_source.go +++ b/pkg/imagetranslation/fake_source.go @@ -16,11 +16,15 @@ limitations under the License. package imagetranslation -import "context" +import ( + "context" + + "github.com/Mirantis/virtlet/pkg/api/types/v1" +) type objectConfig struct { name string - translation ImageTranslation + translation v1.ImageTranslation } var _ TranslationConfig = objectConfig{} @@ -31,12 +35,12 @@ func (c objectConfig) Name() string { } // Payload implements TranslationConfig Payload -func (c objectConfig) Payload() (ImageTranslation, error) { +func (c objectConfig) Payload() (v1.ImageTranslation, error) { return c.translation, nil } type fakeConfigSource struct { - configs map[string]ImageTranslation + configs map[string]v1.ImageTranslation } var _ ConfigSource = fakeConfigSource{} @@ -56,6 +60,6 @@ func (cs fakeConfigSource) Description() string { } // NewFakeConfigSource is a factory for a fake config source -func NewFakeConfigSource(configs map[string]ImageTranslation) ConfigSource { +func NewFakeConfigSource(configs map[string]v1.ImageTranslation) ConfigSource { return &fakeConfigSource{configs: configs} } diff --git a/pkg/imagetranslation/file_source.go b/pkg/imagetranslation/file_source.go index 474fa3b71..a97afd865 100644 --- a/pkg/imagetranslation/file_source.go +++ b/pkg/imagetranslation/file_source.go @@ -23,6 +23,8 @@ import ( "path" "github.com/ghodss/yaml" + + "github.com/Mirantis/virtlet/pkg/api/types/v1" ) type fileConfigSource struct { @@ -65,9 +67,9 @@ func (c fileConfig) Name() string { } // Payload implements TranslationConfig Payload -func (c fileConfig) Payload() (ImageTranslation, error) { +func (c fileConfig) Payload() (v1.ImageTranslation, error) { data, err := ioutil.ReadFile(path.Join(c.cs.configsDirectory, c.name)) - var tr ImageTranslation + var tr v1.ImageTranslation if err != nil { return tr, err } diff --git a/pkg/imagetranslation/interface.go b/pkg/imagetranslation/interface.go index 39eaf4e22..ca9d9703c 100644 --- a/pkg/imagetranslation/interface.go +++ b/pkg/imagetranslation/interface.go @@ -19,80 +19,17 @@ package imagetranslation import ( "context" + "github.com/Mirantis/virtlet/pkg/api/types/v1" "github.com/Mirantis/virtlet/pkg/image" ) -// TranslationRule represents a single translation rule from either name or regexp to Endpoint -type TranslationRule struct { - // Name defines a mapping from a fixed name - Name string `yaml:"name,omitempty" json:"name,omitempty"` - - // Regex defines a mapping from all names that match this regexp. In this case replacements can be used for Endpoint.URL - Regex string `yaml:"regexp,omitempty" json:"regexp,omitempty"` - - // URL is the image URL - URL string `yaml:"url,omitempty" json:"url,omitempty"` - - // Transport is the optional transport profile name to be used for the downloading - Transport string `yaml:"transport,omitempty" json:"transport,omitempty"` -} - -// ImageTranslation is a single translation config with optional prefix name -type ImageTranslation struct { - // Prefix allows to have several config-sets and distinguish them by using `prefix/imageName` notation. Optional. - Prefix string `yaml:"prefix,omitempty" json:"prefix,omitempty"` - - // Rules is a list of translations - Rules []TranslationRule `yaml:"translations" json:"translations"` - - // Transports is a map of available transport profiles available for endpoints - Transports map[string]TransportProfile `yaml:"transports" json:"transports"` -} - -// TransportProfile contains all the http transport settings -type TransportProfile struct { - // MaxRedirects is the maximum number of redirects that downloader is allowed to follow. Default is 9 (download fails on request #10) - MaxRedirects *int `yaml:"maxRedirects,omitempty" json:"maxRedirects,omitempty"` - - // TLS config - TLS *TLSConfig `yaml:"tls,omitempty" json:"tls,omitempty"` - - // TimeoutMilliseconds specifies a time limit in milliseconds for http(s) download request. <= 0 is no timeout (default) - TimeoutMilliseconds int `yaml:"timeout,omitempty" json:"timeout,omitempty"` - - // Proxy server to use for downloading - Proxy string `yaml:"proxy,omitempty" json:"proxy,omitempty"` -} - -// TLSConfig has the TLS transport parameters -type TLSConfig struct { - // Certificates - TLS certificates to use for connection - Certificates []TLSCertificate `yaml:"certificates,omitempty" json:"certificates,omitempty"` - - // ServerName is used to verify the hostname on the returned certificates. Needed when url points to domain that - // differs from CN of certificate - ServerName string `yaml:"serverName,omitempty" json:"serverName,omitempty"` - - // Insecure is a flag to bypass server certificate validation - Insecure bool `yaml:"insecure,omitempty" json:"insecure,omitempty"` -} - -// TLSCertificate has the x509 certificate PEM data with optional PEM private key -type TLSCertificate struct { - // Cert certificate (PEM) block - Cert string `yaml:"cert,omitempty" json:"cert,omitempty"` - - // Key - keypair (PEM) block - Key string `yaml:"key,omitempty" json:"key,omitempty"` -} - // TranslationConfig represents a single config (prefix + rule list) in a config-set type TranslationConfig interface { // Name returns the config name (any string identifier) Name() string // Payload returns ImageTranslation object associated with the config - Payload() (ImageTranslation, error) + Payload() (v1.ImageTranslation, error) } // ConfigSource is the data-source for translation configs diff --git a/pkg/imagetranslation/translator.go b/pkg/imagetranslation/translator.go index 7c4bcb308..fe381b6df 100644 --- a/pkg/imagetranslation/translator.go +++ b/pkg/imagetranslation/translator.go @@ -31,18 +31,19 @@ import ( "github.com/golang/glog" + "github.com/Mirantis/virtlet/pkg/api/types/v1" "github.com/Mirantis/virtlet/pkg/image" ) type imageNameTranslator struct { AllowRegexp bool - translations map[string]*ImageTranslation + translations map[string]*v1.ImageTranslation } // LoadConfigs implements ImageNameTranslator LoadConfigs func (t *imageNameTranslator) LoadConfigs(ctx context.Context, sources ...ConfigSource) { - translations := map[string]*ImageTranslation{} + translations := map[string]*v1.ImageTranslation{} for _, source := range sources { configs, err := source.Configs(ctx) if err != nil { @@ -62,7 +63,7 @@ func (t *imageNameTranslator) LoadConfigs(ctx context.Context, sources ...Config t.translations = translations } -func convertEndpoint(rule TranslationRule, config *ImageTranslation) image.Endpoint { +func convertEndpoint(rule v1.TranslationRule, config *v1.ImageTranslation) image.Endpoint { profile, exists := config.Transports[rule.Transport] if !exists { return image.Endpoint{ diff --git a/pkg/imagetranslation/translator_test.go b/pkg/imagetranslation/translator_test.go index 1e7ef238b..396ef3e98 100644 --- a/pkg/imagetranslation/translator_test.go +++ b/pkg/imagetranslation/translator_test.go @@ -19,13 +19,15 @@ package imagetranslation import ( "context" "testing" + + "github.com/Mirantis/virtlet/pkg/api/types/v1" ) // TestTranslations tests how image names are translated with various translation rules func TestTranslations(t *testing.T) { - configs := map[string]ImageTranslation{ + configs := map[string]v1.ImageTranslation{ "config1": { - Rules: []TranslationRule{ + Rules: []v1.TranslationRule{ { Regex: `^image(\d+)`, URL: "http://example.net/image_$1.qcow2", @@ -42,7 +44,7 @@ func TestTranslations(t *testing.T) { }, "config2": { Prefix: "prod", - Rules: []TranslationRule{ + Rules: []v1.TranslationRule{ { Regex: `^linux/(\d+\.\d+)`, URL: "http://acme.org/linux_$1.qcow2", diff --git a/pkg/imagetranslation/transport_test.go b/pkg/imagetranslation/transport_test.go index f46923e27..f86a30fb4 100644 --- a/pkg/imagetranslation/transport_test.go +++ b/pkg/imagetranslation/transport_test.go @@ -28,15 +28,16 @@ import ( "testing" "time" + "github.com/Mirantis/virtlet/pkg/api/types/v1" "github.com/Mirantis/virtlet/pkg/image" testutils "github.com/Mirantis/virtlet/pkg/utils/testing" ) -func translate(config ImageTranslation, name string, server *httptest.Server) image.Endpoint { +func translate(config v1.ImageTranslation, name string, server *httptest.Server) image.Endpoint { for i, rule := range config.Rules { config.Rules[i].URL = strings.Replace(rule.URL, "%", server.Listener.Addr().String(), 1) } - configs := map[string]ImageTranslation{"config": config} + configs := map[string]v1.ImageTranslation{"config": config} translator := NewImageNameTranslator() translator.LoadConfigs(context.Background(), NewFakeConfigSource(configs)) @@ -47,7 +48,7 @@ func intptr(v int) *int { return &v } -func download(t *testing.T, proto string, config ImageTranslation, name string, server *httptest.Server) { +func download(t *testing.T, proto string, config v1.ImageTranslation, name string, server *httptest.Server) { downloader := image.NewDownloader(proto) if err := downloader.DownloadFile(context.Background(), translate(config, name, server), ioutil.Discard); err != nil { t.Fatal(err) @@ -71,9 +72,9 @@ func TestImageDownload(t *testing.T) { ts := httptest.NewServer(handler) defer ts.Close() - config := ImageTranslation{ + config := v1.ImageTranslation{ Prefix: "test", - Rules: []TranslationRule{ + Rules: []v1.TranslationRule{ { Name: "image1", URL: "http://%/base.qcow2", @@ -103,8 +104,8 @@ func TestImageDownloadRedirects(t *testing.T) { ts := httptest.NewServer(handler) defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image1", URL: "http://%/base.qcow2", @@ -126,7 +127,7 @@ func TestImageDownloadRedirects(t *testing.T) { Transport: "profile4", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "profile1": {MaxRedirects: intptr(0)}, "profile2": {MaxRedirects: intptr(1)}, "profile3": {MaxRedirects: intptr(5)}, @@ -243,14 +244,14 @@ func TestImageDownloadWithProxy(t *testing.T) { ts := httptest.NewServer(handler) defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image1", URL: "example.net/base.qcow2", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "": {Proxy: "http://" + ts.Listener.Addr().String()}, }, } @@ -271,14 +272,14 @@ func TestImageDownloadWithTimeout(t *testing.T) { ts := httptest.NewServer(handler) defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image", URL: "%/base.qcow2", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "": {TimeoutMilliseconds: 250}, }, } @@ -336,18 +337,18 @@ func TestImageDownloadTLS(t *testing.T) { ts.StartTLS() defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image1", URL: "%/base.qcow2", Transport: "tlsProfile", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "tlsProfile": { - TLS: &TLSConfig{ - Certificates: []TLSCertificate{ + TLS: &v1.TLSConfig{ + Certificates: []v1.TLSCertificate{ {Cert: testutils.EncodePEMCert(ca)}, }, }, @@ -389,18 +390,18 @@ func TestImageDownloadTLSWithClientCerts(t *testing.T) { ts.StartTLS() defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image", URL: "%/base.qcow2", Transport: "tlsProfile", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "tlsProfile": { - TLS: &TLSConfig{ - Certificates: []TLSCertificate{ + TLS: &v1.TLSConfig{ + Certificates: []v1.TLSCertificate{ { Cert: testutils.EncodePEMCert(ca), }, @@ -440,18 +441,18 @@ func TestImageDownloadTLSWithServerName(t *testing.T) { ts.StartTLS() defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image", URL: "%/base.qcow2", Transport: "tlsProfile", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "tlsProfile": { - TLS: &TLSConfig{ - Certificates: []TLSCertificate{ + TLS: &v1.TLSConfig{ + Certificates: []v1.TLSCertificate{ {Cert: testutils.EncodePEMCert(ca)}, }, ServerName: "test.corp", @@ -475,17 +476,17 @@ func TestImageDownloadTLSWithoutCertValidation(t *testing.T) { ts.StartTLS() defer ts.Close() - config := ImageTranslation{ - Rules: []TranslationRule{ + config := v1.ImageTranslation{ + Rules: []v1.TranslationRule{ { Name: "image", URL: "%/base.qcow2", Transport: "tlsProfile", }, }, - Transports: map[string]TransportProfile{ + Transports: map[string]v1.TransportProfile{ "tlsProfile": { - TLS: &TLSConfig{Insecure: true}, + TLS: &v1.TLSConfig{Insecure: true}, }, }, } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 631942308..f60d4eaef 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -23,6 +23,7 @@ import ( "github.com/golang/glog" + "github.com/Mirantis/virtlet/pkg/api/types/v1" "github.com/Mirantis/virtlet/pkg/image" "github.com/Mirantis/virtlet/pkg/imagetranslation" "github.com/Mirantis/virtlet/pkg/libvirttools" @@ -135,7 +136,7 @@ func (v *VirtletManager) Run() error { var translator image.Translator if !v.config.SkipImageTranslation { - if err = imagetranslation.RegisterCustomResourceType(); err != nil { + if err = v1.RegisterCustomResourceTypes(); err != nil { return fmt.Errorf("failed to register image translation CRD: %v", err) } translator = imagetranslation.GetDefaultImageTranslator(v.config.ImageTranslationConfigsDir) diff --git a/tests/e2e/framework/controller.go b/tests/e2e/framework/controller.go index a909179b9..00b1cb641 100644 --- a/tests/e2e/framework/controller.go +++ b/tests/e2e/framework/controller.go @@ -28,7 +28,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "github.com/Mirantis/virtlet/pkg/imagetranslation" + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/types/v1" ) var ClusterURL = flag.String("cluster-url", "http://127.0.0.1:8080", "apiserver URL") @@ -91,12 +91,12 @@ func (c *Controller) Finalize() error { return c.client.Namespaces().Delete(c.namespace.Name, nil) } -func (c *Controller) CreateVirtletImageMapping(mapping imagetranslation.VirtletImageMapping) (*imagetranslation.VirtletImageMapping, error) { - client, err := imagetranslation.GetCRDRestClient(c.restConfig) +func (c *Controller) CreateVirtletImageMapping(mapping virtlet_v1.VirtletImageMapping) (*virtlet_v1.VirtletImageMapping, error) { + client, err := virtlet_v1.GetCRDRestClient(c.restConfig) if err != nil { return nil, err } - var result imagetranslation.VirtletImageMapping + var result virtlet_v1.VirtletImageMapping err = client.Post(). Resource("virtletimagemappings"). Namespace("kube-system"). @@ -109,7 +109,7 @@ func (c *Controller) CreateVirtletImageMapping(mapping imagetranslation.VirtletI } func (c *Controller) DeleteVirtletImageMapping(name string) error { - client, err := imagetranslation.GetCRDRestClient(c.restConfig) + client, err := virtlet_v1.GetCRDRestClient(c.restConfig) if err != nil { return err } diff --git a/tests/e2e/image_name_translation_test.go b/tests/e2e/image_name_translation_test.go index d241edbca..d5b560f08 100644 --- a/tests/e2e/image_name_translation_test.go +++ b/tests/e2e/image_name_translation_test.go @@ -22,7 +22,7 @@ import ( . "github.com/onsi/gomega" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/Mirantis/virtlet/pkg/imagetranslation" + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/types/v1" . "github.com/Mirantis/virtlet/tests/e2e/ginkgo-ext" ) @@ -30,12 +30,12 @@ var _ = Describe("Image URL", func() { var vimName string BeforeAll(func() { - vim, err := controller.CreateVirtletImageMapping(imagetranslation.VirtletImageMapping{ + vim, err := controller.CreateVirtletImageMapping(virtlet_v1.VirtletImageMapping{ ObjectMeta: meta_v1.ObjectMeta{ GenerateName: "virtlet-e2e-", }, - Spec: imagetranslation.ImageTranslation{ - Rules: []imagetranslation.TranslationRule{ + Spec: virtlet_v1.ImageTranslation{ + Rules: []virtlet_v1.TranslationRule{ { Name: "test-image", URL: *vmImageLocation, From 3829b3ab6f231c40241a0b00ed0185b8d4b0afec Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 5 Jun 2018 17:45:13 +0300 Subject: [PATCH 02/17] Implement per-node config Also, use k8s.io/code-generator for CRDs. --- build/custom-boilerplate.go.txt | 15 + build/update-codegen.sh | 17 + cmd/virtlet/virtlet.go | 103 ++-- deploy/data/virtlet-ds.yaml | 115 ++--- glide.lock | 33 +- glide.yaml | 12 +- images/image_skel/prepare-node.sh | 7 + images/image_skel/start.sh | 18 +- pkg/api/{types => virtlet.k8s}/v1/client.go | 2 +- pkg/api/virtlet.k8s/v1/doc.go | 22 + .../{types => virtlet.k8s}/v1/imagemapping.go | 61 +-- pkg/api/{types => virtlet.k8s}/v1/register.go | 68 ++- pkg/api/virtlet.k8s/v1/virtletconfig.go | 91 ++++ .../virtlet.k8s/v1/zz_generated.deepcopy.go | 439 ++++++++++++++++++ pkg/client/clientset/versioned/clientset.go | 100 ++++ pkg/client/clientset/versioned/doc.go | 20 + .../versioned/fake/clientset_generated.go | 81 ++++ pkg/client/clientset/versioned/fake/doc.go | 20 + .../clientset/versioned/fake/register.go | 54 +++ pkg/client/clientset/versioned/scheme/doc.go | 20 + .../clientset/versioned/scheme/register.go | 54 +++ .../versioned/typed/virtlet.k8s/v1/doc.go | 20 + .../typed/virtlet.k8s/v1/fake/doc.go | 20 + .../v1/fake/fake_virtlet.k8s_client.go | 44 ++ .../v1/fake/fake_virtletconfigmapping.go | 128 +++++ .../v1/fake/fake_virtletimagemapping.go | 128 +++++ .../virtlet.k8s/v1/generated_expansion.go | 23 + .../virtlet.k8s/v1/virtlet.k8s_client.go | 95 ++++ .../virtlet.k8s/v1/virtletconfigmapping.go | 157 +++++++ .../virtlet.k8s/v1/virtletimagemapping.go | 157 +++++++ .../informers/externalversions/factory.go | 131 ++++++ .../informers/externalversions/generic.go | 64 +++ .../internalinterfaces/factory_interfaces.go | 38 ++ .../externalversions/virtlet.k8s/interface.go | 46 ++ .../virtlet.k8s/v1/interface.go | 52 +++ .../virtlet.k8s/v1/virtletconfigmapping.go | 89 ++++ .../virtlet.k8s/v1/virtletimagemapping.go | 89 ++++ .../virtlet.k8s/v1/expansion_generated.go | 35 ++ .../virtlet.k8s/v1/virtletconfigmapping.go | 94 ++++ .../virtlet.k8s/v1/virtletimagemapping.go | 94 ++++ ...igForNode__mapping_by_node_labels.out.yaml | 17 + ...mapping_by_node_labels__no_match_.out.yaml | 17 + ...nfigForNode__mapping_by_node_name.out.yaml | 17 + ...__mapping_by_node_name__no_match_.out.yaml | 17 + ..._by_node_name_and_multiple_labels.out.yaml | 17 + ...ultiple_labels_and_a_local_config.out.yaml | 17 + .../TestConfigForNode__no_mappings.out.yaml | 17 + pkg/config/TestDefaultVirtletConfig.out.yaml | 17 + pkg/config/TestLoadMappings.out.yaml | 17 + .../TestMergeConfigs__all_cli_opts.out.yaml | 15 + ...estMergeConfigs__all_cli_opts__env.out.txt | 15 + ..._opts_and_explicit_default_config.out.yaml | 17 + ...s_and_explicit_default_config__env.out.txt | 16 + .../TestMergeConfigs__defaults.out.yaml | 1 + .../TestMergeConfigs__defaults__env.out.txt | 0 ...ults__explicitly_set_as_a_config_.out.yaml | 17 + ...__explicitly_set_as_a_config___env.out.txt | 16 + ...estMergeConfigs__opts_and_configs.out.yaml | 5 + ...ergeConfigs__opts_and_configs__env.out.txt | 5 + pkg/config/config.go | 266 +++++++++++ pkg/config/config_test.go | 330 +++++++++++++ pkg/config/fields.go | 268 +++++++++++ pkg/imagetranslation/crd_source.go | 2 +- pkg/imagetranslation/fake_source.go | 4 +- pkg/imagetranslation/file_source.go | 4 +- pkg/imagetranslation/interface.go | 6 +- pkg/imagetranslation/translator.go | 23 +- pkg/imagetranslation/translator_test.go | 8 +- pkg/imagetranslation/transport_test.go | 4 +- pkg/libvirttools/virtualization.go | 136 +++--- pkg/libvirttools/virtualization_test.go | 14 +- pkg/manager/manager.go | 94 ++-- pkg/manager/runtime_test.go | 19 +- pkg/nettools/nettools.go | 26 +- pkg/nettools/nettools_test.go | 6 +- pkg/tapmanager/tapfdsource.go | 13 +- pkg/tools/TestGenCommand__compat.out.yaml | 117 +++-- pkg/tools/TestGenCommand__compat_dev.out.yaml | 117 +++-- pkg/tools/TestGenCommand__dev.out.yaml | 117 +++-- pkg/tools/TestGenCommand__plain.out.yaml | 115 ++--- pkg/tools/TestGenCommand__tag.out.yaml | 117 +++-- pkg/tools/bindata.go | 4 +- pkg/tools/kubeclient.go | 2 +- pkg/tools/settings.go | 39 +- pkg/tools/version.go | 2 +- pkg/tools/version_test.go | 20 +- pkg/utils/k8s_client.go | 42 ++ tests/e2e/framework/controller.go | 2 +- tests/e2e/image_name_translation_test.go | 4 +- tests/integration/manager.go | 29 +- tests/network/vm_network_test.go | 4 +- 91 files changed, 4260 insertions(+), 810 deletions(-) create mode 100644 build/custom-boilerplate.go.txt create mode 100755 build/update-codegen.sh rename pkg/api/{types => virtlet.k8s}/v1/client.go (92%) create mode 100644 pkg/api/virtlet.k8s/v1/doc.go rename pkg/api/{types => virtlet.k8s}/v1/imagemapping.go (76%) rename pkg/api/{types => virtlet.k8s}/v1/register.go (50%) create mode 100644 pkg/api/virtlet.k8s/v1/virtletconfig.go create mode 100644 pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/clientset.go create mode 100644 pkg/client/clientset/versioned/doc.go create mode 100644 pkg/client/clientset/versioned/fake/clientset_generated.go create mode 100644 pkg/client/clientset/versioned/fake/doc.go create mode 100644 pkg/client/clientset/versioned/fake/register.go create mode 100644 pkg/client/clientset/versioned/scheme/doc.go create mode 100644 pkg/client/clientset/versioned/scheme/register.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtlet.k8s_client.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletconfigmapping.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletimagemapping.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtlet.k8s_client.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletconfigmapping.go create mode 100644 pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletimagemapping.go create mode 100644 pkg/client/informers/externalversions/factory.go create mode 100644 pkg/client/informers/externalversions/generic.go create mode 100644 pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 pkg/client/informers/externalversions/virtlet.k8s/interface.go create mode 100644 pkg/client/informers/externalversions/virtlet.k8s/v1/interface.go create mode 100644 pkg/client/informers/externalversions/virtlet.k8s/v1/virtletconfigmapping.go create mode 100644 pkg/client/informers/externalversions/virtlet.k8s/v1/virtletimagemapping.go create mode 100644 pkg/client/listers/virtlet.k8s/v1/expansion_generated.go create mode 100644 pkg/client/listers/virtlet.k8s/v1/virtletconfigmapping.go create mode 100644 pkg/client/listers/virtlet.k8s/v1/virtletimagemapping.go create mode 100755 pkg/config/TestConfigForNode__mapping_by_node_labels.out.yaml create mode 100755 pkg/config/TestConfigForNode__mapping_by_node_labels__no_match_.out.yaml create mode 100755 pkg/config/TestConfigForNode__mapping_by_node_name.out.yaml create mode 100755 pkg/config/TestConfigForNode__mapping_by_node_name__no_match_.out.yaml create mode 100755 pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels.out.yaml create mode 100755 pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels_and_a_local_config.out.yaml create mode 100755 pkg/config/TestConfigForNode__no_mappings.out.yaml create mode 100755 pkg/config/TestDefaultVirtletConfig.out.yaml create mode 100755 pkg/config/TestLoadMappings.out.yaml create mode 100755 pkg/config/TestMergeConfigs__all_cli_opts.out.yaml create mode 100755 pkg/config/TestMergeConfigs__all_cli_opts__env.out.txt create mode 100755 pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config.out.yaml create mode 100755 pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config__env.out.txt create mode 100755 pkg/config/TestMergeConfigs__defaults.out.yaml create mode 100755 pkg/config/TestMergeConfigs__defaults__env.out.txt create mode 100755 pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config_.out.yaml create mode 100755 pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config___env.out.txt create mode 100755 pkg/config/TestMergeConfigs__opts_and_configs.out.yaml create mode 100755 pkg/config/TestMergeConfigs__opts_and_configs__env.out.txt create mode 100644 pkg/config/config.go create mode 100644 pkg/config/config_test.go create mode 100644 pkg/config/fields.go diff --git a/build/custom-boilerplate.go.txt b/build/custom-boilerplate.go.txt new file mode 100644 index 000000000..801ff86dc --- /dev/null +++ b/build/custom-boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright YEAR Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ diff --git a/build/update-codegen.sh b/build/update-codegen.sh new file mode 100755 index 000000000..f10fa9b27 --- /dev/null +++ b/build/update-codegen.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# TODO: move this to cmd.sh once we upgrade to Go 1.10 + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_ROOT="$(dirname ${BASH_SOURCE})/.." +CODEGEN_PKG="${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ${GOPATH}/src/k8s.io/code-generator)}" + +vendor/k8s.io/code-generator/generate-groups.sh all \ + github.com/Mirantis/virtlet/pkg/client github.com/Mirantis/virtlet/pkg/api \ + virtlet.k8s:v1 \ + --go-header-file "${SCRIPT_ROOT}/build/custom-boilerplate.go.txt" + +# fix import url case issues +find "${SCRIPT_ROOT}/pkg/client" -name '*.go' -exec sed -i 's@github\.com/mirantis/virtlet@github\.com/Mirantis/virtlet@g' '{}' \; diff --git a/cmd/virtlet/virtlet.go b/cmd/virtlet/virtlet.go index f05931f48..4625c1c80 100644 --- a/cmd/virtlet/virtlet.go +++ b/cmd/virtlet/virtlet.go @@ -17,15 +17,17 @@ limitations under the License. package main import ( - "flag" "math/rand" "os" "os/exec" "time" "github.com/golang/glog" + flag "github.com/spf13/pflag" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/cni" + "github.com/Mirantis/virtlet/pkg/config" "github.com/Mirantis/virtlet/pkg/libvirttools" "github.com/Mirantis/virtlet/pkg/manager" "github.com/Mirantis/virtlet/pkg/tapmanager" @@ -33,71 +35,49 @@ import ( "github.com/Mirantis/virtlet/pkg/version" ) +const ( + wantTapManagerEnv = "WANT_TAP_MANAGER" + nodeNameEnv = "KUBE_NODE_NAME" +) + var ( - libvirtURI = flag.String("libvirt-uri", "qemu:///system", - "Libvirt connection URI") - imageDir = flag.String("image dir", "/var/lib/virtlet/images", - "Image directory") - boltPath = flag.String("bolt-path", "/var/lib/virtlet/virtlet.db", - "Path to the bolt database file") - listen = flag.String("listen", "/run/virtlet.sock", - "The unix socket to listen on, e.g. /run/virtlet.sock") - cniPluginsDir = flag.String("cni-bin-dir", "/opt/cni/bin", - "Path to CNI plugin binaries") - cniConfigsDir = flag.String("cni-conf-dir", "/etc/cni/net.d", - "Location of CNI configurations (first file name in lexicographic order will be chosen)") - imageDownloadProtocol = flag.String("image-download-protocol", "https", - "Image download protocol. Can be https (default) or http.") - rawDevices = flag.String("raw-devices", "loop*", - "Comma separated list of raw device glob patterns to which VM can have an access (with skipped /dev/ prefix)") - fdServerSocketPath = flag.String("fd-server-socket-path", "/var/lib/virtlet/tapfdserver.sock", - "Path to fd server socket") - imageTranslationConfigsDir = flag.String("image-translations-dir", "", - "Image name translation configs directory") + dumpConfig = flag.Bool("dump-config", false, "Dump node-specific Virtlet config as a shell script and exit") displayVersion = flag.Bool("version", false, "Display version and exit") versionFormat = flag.String("version-format", "text", "Version format to use (text, short, json, yaml)") ) -const ( - WantTapManagerEnv = "WANT_TAP_MANAGER" -) +func configWithDefaults(cfg *v1.VirtletConfig) *v1.VirtletConfig { + r := config.GetDefaultConfig() + config.Override(r, cfg) + return r +} -func runVirtlet() { - manager := manager.NewVirtletManager(&manager.VirtletConfig{ - FDServerSocketPath: *fdServerSocketPath, - DatabasePath: *boltPath, - DownloadProtocol: *imageDownloadProtocol, - ImageDir: *imageDir, - ImageTranslationConfigsDir: *imageTranslationConfigsDir, - LibvirtURI: *libvirtURI, - RawDevices: *rawDevices, - CRISocketPath: *listen, - DisableLogging: os.Getenv("VIRTLET_DISABLE_LOGGING") != "", - }) +func runVirtlet(config *v1.VirtletConfig) { + manager := manager.NewVirtletManager(config, nil) if err := manager.Run(); err != nil { glog.Errorf("Error: %v", err) os.Exit(1) } } -func runTapManager() { - cniClient, err := cni.NewClient(*cniPluginsDir, *cniConfigsDir) +func runTapManager(config *v1.VirtletConfig) { + cniClient, err := cni.NewClient(*config.CNIPluginDir, *config.CNIConfigDir) if err != nil { glog.Errorf("Error initializing CNI client: %v", err) os.Exit(1) } - src, err := tapmanager.NewTapFDSource(cniClient) + src, err := tapmanager.NewTapFDSource(cniClient, *config.EnableSriov, *config.CalicoSubnetSize) if err != nil { glog.Errorf("Error creating tap fd source: %v", err) os.Exit(1) } - os.Remove(*fdServerSocketPath) // FIXME - s := tapmanager.NewFDServer(*fdServerSocketPath, src) + os.Remove(*config.FDServerSocketPath) // FIXME + s := tapmanager.NewFDServer(*config.FDServerSocketPath, src) if err = s.Serve(); err != nil { glog.Errorf("FD server returned error: %v", err) os.Exit(1) } - if err := libvirttools.ChownForEmulator(*fdServerSocketPath); err != nil { + if err := libvirttools.ChownForEmulator(*config.FDServerSocketPath); err != nil { glog.Warningf("Couldn't set tapmanager socket permissions: %v", err) } for { @@ -105,9 +85,9 @@ func runTapManager() { } } -func startTapManagerProcess() { +func startTapManagerProcess(config *v1.VirtletConfig) { cmd := exec.Command(os.Args[0], os.Args[1:]...) - cmd.Env = append(os.Environ(), WantTapManagerEnv+"=1") + cmd.Env = append(os.Environ(), wantTapManagerEnv+"=1") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr // Here we make this process die with the main Virtlet process. @@ -133,17 +113,34 @@ func printVersion() { func main() { utils.HandleNsFixReexec() + clientCfg := utils.BindFlags(flag.CommandLine) + var cb *config.ConfigBinder + cb = config.NewConfigBinder(flag.CommandLine) flag.Parse() - if *displayVersion { - printVersion() - os.Exit(0) - } + localConfig := cb.GetConfig() rand.Seed(time.Now().UnixNano()) - if os.Getenv(WantTapManagerEnv) == "" { - startTapManagerProcess() - runVirtlet() - } else { - runTapManager() + switch { + case os.Getenv(wantTapManagerEnv) != "": + localConfig = configWithDefaults(localConfig) + runTapManager(localConfig) + case *displayVersion: + printVersion() + case *dumpConfig: + nodeConfig := config.NewNodeConfig(clientCfg) + nodeName := os.Getenv(nodeNameEnv) + cfg, err := nodeConfig.LoadConfig(localConfig, nodeName) + if err != nil { + glog.Warning("Failed to load per-node configs, using local config only: %v", err) + cfg = localConfig + } + if _, err := os.Stdout.Write([]byte(config.DumpEnv(cfg))); err != nil { + glog.Errorf("Error writing config: %v", err) + os.Exit(1) + } + default: + localConfig = configWithDefaults(localConfig) + startTapManagerProcess(localConfig) + runVirtlet(localConfig) } } diff --git a/deploy/data/virtlet-ds.yaml b/deploy/data/virtlet-ds.yaml index 2fc8d8944..b384c1f39 100644 --- a/deploy/data/virtlet-ds.yaml +++ b/deploy/data/virtlet-ds.yaml @@ -54,15 +54,66 @@ spec: mountPath: /host-var-lib - name: dev mountPath: /dev + - mountPath: /var/lib/virtlet + name: virtlet securityContext: privileged: true env: + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName - name: VIRTLET_DISABLE_KVM valueFrom: configMapKeyRef: name: virtlet-config key: disable_kvm optional: true + - name: VIRTLET_SRIOV_SUPPORT + valueFrom: + configMapKeyRef: + name: virtlet-config + key: sriov_support + optional: true + - name: VIRTLET_DOWNLOAD_PROTOCOL + valueFrom: + configMapKeyRef: + name: virtlet-config + key: download_protocol + optional: true + - name: VIRTLET_LOGLEVEL + valueFrom: + configMapKeyRef: + name: virtlet-config + key: loglevel + optional: true + - name: VIRTLET_CALICO_SUBNET + valueFrom: + configMapKeyRef: + name: virtlet-config + key: calico-subnet + optional: true + - name: IMAGE_REGEXP_TRANSLATION + valueFrom: + configMapKeyRef: + name: virtlet-config + key: image_regexp_translation + optional: true + - name: VIRTLET_RAW_DEVICES + valueFrom: + configMapKeyRef: + name: virtlet-config + key: raw_devices + optional: true + - name: VIRTLET_DISABLE_LOGGING + valueFrom: + configMapKeyRef: + name: virtlet-config + key: disable_logging + optional: true + - name: VIRTLET_IMAGE_TRANSLATIONS_DIR + value: /etc/virtlet/images containers: - name: libvirt @@ -100,19 +151,6 @@ spec: mountPath: /dev securityContext: privileged: true - env: - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - name: virtlet-config - key: sriov_support - optional: true - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - name: virtlet-config - key: disable_kvm - optional: true readinessProbe: exec: command: @@ -153,57 +191,6 @@ spec: mountPath: /var/log/pods securityContext: privileged: true - env: - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - name: virtlet-config - key: disable_kvm - optional: true - - name: VIRTLET_DOWNLOAD_PROTOCOL - valueFrom: - configMapKeyRef: - name: virtlet-config - key: download_protocol - optional: true - - name: VIRTLET_LOGLEVEL - valueFrom: - configMapKeyRef: - name: virtlet-config - key: loglevel - optional: true - - name: VIRTLET_CALICO_SUBNET - valueFrom: - configMapKeyRef: - name: virtlet-config - key: calico-subnet - optional: true - - name: IMAGE_REGEXP_TRANSLATION - valueFrom: - configMapKeyRef: - name: virtlet-config - key: image_regexp_translation - optional: true - - name: VIRTLET_DISABLE_LOGGING - valueFrom: - configMapKeyRef: - name: virtlet-config - key: disable_logging - optional: true - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - name: virtlet-config - key: sriov_support - optional: true - - name: VIRTLET_RAW_DEVICES - valueFrom: - configMapKeyRef: - name: virtlet-config - key: raw_devices - optional: true - - name: IMAGE_TRANSLATIONS_DIR - value: /etc/virtlet/images readinessProbe: exec: command: diff --git a/glide.lock b/glide.lock index c11133160..40f11ce70 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 7143f5f6fd8cbd7d465fe0be517bb010ea49fbe033bd2b13b6b41842145fc0e4 -updated: 2018-05-17T23:37:53.451149641+03:00 +hash: e779019b616d563bb6ca86c655b1e4c6a88bc62c4b4f7aa357d5d48debe73fe2 +updated: 2018-06-05T12:01:20.9782965+03:00 imports: - name: github.com/boltdb/bolt version: 583e8937c61f1af6513608ccc75c97b6abdf4ff9 @@ -116,8 +116,6 @@ imports: - ptypes/any - ptypes/duration - ptypes/timestamp -- name: github.com/google/btree - version: 7d79101e329e5a3adf994758c578dab82b90c017 - name: github.com/google/gofuzz version: 44d81051d367757e1c7c6a5a86423ece9afcf63c - name: github.com/googleapis/gnostic @@ -126,10 +124,6 @@ imports: - OpenAPIv2 - compiler - extensions -- name: github.com/gregjones/httpcache - version: 787624de3eb7bd915c329cba748687a3b22666a6 - subpackages: - - diskcache - name: github.com/hashicorp/golang-lru version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 subpackages: @@ -144,8 +138,8 @@ imports: version: bcac9884e7502bb2b474c0339d889cb981a2f27f - name: github.com/json-iterator/go version: 13f86432b882000a51c6e610c620974462691a97 -- name: github.com/juju/ratelimit - version: 5b9ff866471762aa2ab2dced63c9fb6f53921342 +- name: github.com/kballard/go-shellquote + version: 95032a82bc518f77982ea72343cc1ade730072f0 - name: github.com/kr/pty version: f7ee69f31298ecbe5d2b349c711e2547a617d398 - name: github.com/libvirt/libvirt-go @@ -189,8 +183,6 @@ imports: - types - name: github.com/opencontainers/go-digest version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb -- name: github.com/peterbourgon/diskv - version: 5f041e8faa004a95c88a202771f4cc3e991971e6 - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/pmezard/go-difflib @@ -254,6 +246,12 @@ imports: subpackages: - unix - windows +- name: golang.org/x/time + version: f51c12702a4d776e4c1fa9b0fabab841babae631 + subpackages: + - rate +- name: golang.org/x/tools + version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32 - name: google.golang.org/grpc version: 777daa17ff9b5daef1cfdf915088a2ada3332bf0 subpackages: @@ -274,7 +272,7 @@ imports: - json - jwt - name: gopkg.in/yaml.v2 - version: 86f5ed62f8a0ee96bd888d2efdfd6d4fb100a4eb + version: 670d4cfef0544295bc27a114dbac37980d83185a - name: k8s.io/api version: 73d903622b7391f3312dcbac6483fed484e185f8 subpackages: @@ -467,7 +465,7 @@ imports: - plugin/pkg/authenticator/token/webhook - plugin/pkg/authorizer/webhook - name: k8s.io/client-go - version: 78700dec6369ba22221b72770783300f143df150 + version: 33f2870a2b83179c823ddc90e5513f9e5fe43b38 subpackages: - discovery - discovery/fake @@ -595,7 +593,10 @@ imports: - listers/storage/v1 - listers/storage/v1alpha1 - listers/storage/v1beta1 + - pkg/apis/clientauthentication + - pkg/apis/clientauthentication/v1alpha1 - pkg/version + - plugin/pkg/client/auth/exec - rest - rest/fake - rest/watch @@ -621,6 +622,10 @@ imports: - util/homedir - util/integer - util/retry +- name: k8s.io/code-generator + version: 7ead8f38b01cf8653249f5af80ce7b2c8aba12e2 +- name: k8s.io/gengo + version: 01a732e01d00cb9a81bb0ca050d3e6d2b947927b - name: k8s.io/kube-openapi version: 50ae88d24ede7b8bad68e23c805b5d3da5c8abaf subpackages: diff --git a/glide.yaml b/glide.yaml index 3b9fa8540..0075dae51 100644 --- a/glide.yaml +++ b/glide.yaml @@ -60,7 +60,7 @@ import: - package: github.com/spf13/pflag version: 4c012f6dcd9546820e378d0bdda4d8fc772cdfea - package: k8s.io/client-go - version: ~6.0.0 + version: kubernetes-1.10.2 - package: k8s.io/api version: kubernetes-1.10.2 - package: k8s.io/apimachinery @@ -69,3 +69,13 @@ import: version: kubernetes-1.10.2 - package: k8s.io/kubernetes version: v1.10.2 +- package: github.com/kballard/go-shellquote + version: 95032a82bc518f77982ea72343cc1ade730072f0 +- package: k8s.io/code-generator + version: kubernetes-1.10.2 +# glide fails to parse Godeps/Godeps.json in code-generator for some reason, +# so some deps copied from there follow +- package: k8s.io/gengo + version: 01a732e01d00cb9a81bb0ca050d3e6d2b947927b +- package: golang.org/x/tools + version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32 diff --git a/images/image_skel/prepare-node.sh b/images/image_skel/prepare-node.sh index b97530fb9..d3b93c2dd 100755 --- a/images/image_skel/prepare-node.sh +++ b/images/image_skel/prepare-node.sh @@ -9,6 +9,13 @@ if [[ -f /dind/prepare-node.sh && ! ( ${0} =~ /dind/ ) ]]; then exec /dind/prepare-node.sh "$@" fi +verbose= +if [[ ${VIRTLET_LOGLEVEL:-} ]]; then + verbose="--v ${VIRTLET_LOGLEVEL}" +fi +/usr/local/bin/virtlet --dump-config ${verbose} >/var/lib/virtlet/config.sh +. /var/lib/virtlet/config.sh + PLUGIN_DIR=/kubelet-volume-plugins/virtlet~flexvolume_driver if [[ ! -d ${PLUGIN_DIR} ]]; then diff --git a/images/image_skel/start.sh b/images/image_skel/start.sh index d61122fd2..859bd0ff2 100755 --- a/images/image_skel/start.sh +++ b/images/image_skel/start.sh @@ -4,16 +4,12 @@ set -o nounset set -o pipefail set -o errtrace -if [[ -f /dind/virtlet ]]; then - ln -fs /dind/virtlet /usr/local/bin/virtlet +if [[ /var/lib/virtlet/config.sh ]]; then + . /var/lib/virtlet/config.sh fi -PROTOCOL="${VIRTLET_DOWNLOAD_PROTOCOL:-https}" -IMAGE_TRANSLATIONS_DIR="${IMAGE_TRANSLATIONS_DIR:-}" - -opts=(-v=${VIRTLET_LOGLEVEL:-3} -logtostderr=true -image-download-protocol="${PROTOCOL}" -image-translations-dir="${IMAGE_TRANSLATIONS_DIR}") -if [[ ${VIRTLET_RAW_DEVICES:-} ]]; then - opts+=(-raw-devices "${VIRTLET_RAW_DEVICES}") +if [[ -f /dind/virtlet ]]; then + ln -fs /dind/virtlet /usr/local/bin/virtlet fi while [ ! -S /var/run/libvirt/libvirt-sock ] ; do @@ -21,4 +17,8 @@ while [ ! -S /var/run/libvirt/libvirt-sock ] ; do sleep 0.3 done -/usr/local/bin/virtlet "${opts[@]}" +verbose= +if [[ ${VIRTLET_LOGLEVEL:-} ]]; then + verbose="--v ${VIRTLET_LOGLEVEL}" +fi +/usr/local/bin/virtlet ${verbose} diff --git a/pkg/api/types/v1/client.go b/pkg/api/virtlet.k8s/v1/client.go similarity index 92% rename from pkg/api/types/v1/client.go rename to pkg/api/virtlet.k8s/v1/client.go index 7ca6d2765..986441489 100644 --- a/pkg/api/types/v1/client.go +++ b/pkg/api/virtlet.k8s/v1/client.go @@ -24,5 +24,5 @@ import ( // GetCRDRestClient returns ReST client that can be used to work with virtlet CRDs func GetCRDRestClient(cfg *rest.Config) (*rest.RESTClient, error) { - return utils.GetK8sRestClient(cfg, scheme, &schemeGroupVersion) + return utils.GetK8sRestClient(cfg, scheme, &SchemeGroupVersion) } diff --git a/pkg/api/virtlet.k8s/v1/doc.go b/pkg/api/virtlet.k8s/v1/doc.go new file mode 100644 index 000000000..b2b67a60f --- /dev/null +++ b/pkg/api/virtlet.k8s/v1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package,register + +// Package v1 is the v1 version of the API. +// +groupName=virtlet.k8s + +package v1 diff --git a/pkg/api/types/v1/imagemapping.go b/pkg/api/virtlet.k8s/v1/imagemapping.go similarity index 76% rename from pkg/api/types/v1/imagemapping.go rename to pkg/api/virtlet.k8s/v1/imagemapping.go index 2a46c4729..bbcbb0b14 100644 --- a/pkg/api/types/v1/imagemapping.go +++ b/pkg/api/virtlet.k8s/v1/imagemapping.go @@ -18,7 +18,6 @@ package v1 import ( meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" ) // TranslationRule represents a single translation rule from either name or regexp to Endpoint @@ -85,68 +84,30 @@ type TLSCertificate struct { Key string `yaml:"key,omitempty" json:"key,omitempty"` } -// VirtletImageMapping represents an ImageTranslation wrapped in k8s object +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VirtletImageMapping represents an ImageTranslation wrapped in k8s object. type VirtletImageMapping struct { meta_v1.TypeMeta `json:",inline"` meta_v1.ObjectMeta `json:"metadata"` Spec ImageTranslation `json:"spec"` } -// DeepCopyObject implements DeepCopyObject method of runtime.Object interface -func (vim *VirtletImageMapping) DeepCopyObject() runtime.Object { - if vim == nil { - return nil - } - r := *vim - if vim.Spec.Transports == nil { - return &r - } - - transportMap := make(map[string]TransportProfile) - for k, tr := range vim.Spec.Transports { - if tr.MaxRedirects != nil { - redirs := *tr.MaxRedirects - tr.MaxRedirects = &redirs - } - if tr.TLS != nil { - tls := *tr.TLS - tr.TLS = &tls - } - transportMap[k] = tr - } - return &r -} - -// Name implements TranslationConfig Name -func (vim *VirtletImageMapping) Name() string { - return vim.ObjectMeta.Name -} +// ConfigName returns the name of the config. +func (vim *VirtletImageMapping) ConfigName() string { return vim.Name } -// Payload implements TranslationConfig Payload +// Payload returns the actual translation for the mapping. func (vim *VirtletImageMapping) Payload() (ImageTranslation, error) { return vim.Spec, nil } -// VirtletImageMappingList is a k8s representation of list of translation configs +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VirtletImageMappingList is a k8s representation of list of translation configs. type VirtletImageMappingList struct { meta_v1.TypeMeta `json:",inline"` meta_v1.ListMeta `json:"metadata"` Items []VirtletImageMapping `json:"items"` } - -// DeepCopyObject implements DeepCopyObject method of runtime.Object interface -func (l *VirtletImageMappingList) DeepCopyObject() runtime.Object { - if l == nil { - return l - } - r := &VirtletImageMappingList{ - TypeMeta: l.TypeMeta, - ListMeta: l.ListMeta, - } - for _, vim := range l.Items { - r.Items = append(r.Items, *vim.DeepCopyObject().(*VirtletImageMapping)) - } - return r -} - -// TODO: update '... implements ...' comments in this file diff --git a/pkg/api/types/v1/register.go b/pkg/api/virtlet.k8s/v1/register.go similarity index 50% rename from pkg/api/types/v1/register.go rename to pkg/api/virtlet.k8s/v1/register.go index a1852a3fc..0e6e3fc3a 100644 --- a/pkg/api/types/v1/register.go +++ b/pkg/api/virtlet.k8s/v1/register.go @@ -35,24 +35,48 @@ const ( var ( schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) scheme = runtime.NewScheme() - schemeGroupVersion = schema.GroupVersion{Group: groupName, Version: version} + SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: version} + AddToScheme = schemeBuilder.AddToScheme ) +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + // RegisterCustomResourceTypes registers custom resource definition for VirtletImageMapping kind in k8s func RegisterCustomResourceTypes() error { - crd := apiextensionsv1beta1.CustomResourceDefinition{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "virtletimagemappings." + groupName, + crds := []apiextensionsv1beta1.CustomResourceDefinition{ + { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "virtletimagemappings." + groupName, + }, + Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ + Group: groupName, + Version: version, + Scope: apiextensionsv1beta1.NamespaceScoped, + Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ + Plural: "virtletimagemappings", + Singular: "virtletimagemapping", + Kind: "VirtletImageMapping", + ShortNames: []string{"vim"}, + }, + }, }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: groupName, - Version: version, - Scope: apiextensionsv1beta1.NamespaceScoped, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Plural: "virtletimagemappings", - Singular: "virtletimagemapping", - Kind: "VirtletImageMapping", - ShortNames: []string{"vim"}, + { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "virtletconfigmappings." + groupName, + }, + Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ + Group: groupName, + Version: version, + Scope: apiextensionsv1beta1.NamespaceScoped, + Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ + Plural: "virtletconfigmappings", + Singular: "virtletconfigmapping", + Kind: "VirtletConfigMapping", + ShortNames: []string{"vcm"}, + }, }, }, } @@ -65,19 +89,25 @@ func RegisterCustomResourceTypes() error { panic(err) } - _, err = extensionsClientSet.ApiextensionsV1beta1().CustomResourceDefinitions().Create(&crd) - if err == nil || apierrors.IsAlreadyExists(err) { - return nil + for _, crd := range crds { + _, err = extensionsClientSet.ApiextensionsV1beta1().CustomResourceDefinitions().Create(&crd) + if err == nil || apierrors.IsAlreadyExists(err) { + continue + } + return err } - return err + + return nil } func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(schemeGroupVersion, + scheme.AddKnownTypes(SchemeGroupVersion, &VirtletImageMapping{}, &VirtletImageMappingList{}, + &VirtletConfigMapping{}, + &VirtletConfigMappingList{}, ) - meta_v1.AddToGroupVersion(scheme, schemeGroupVersion) + meta_v1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } diff --git a/pkg/api/virtlet.k8s/v1/virtletconfig.go b/pkg/api/virtlet.k8s/v1/virtletconfig.go new file mode 100644 index 000000000..38f76d553 --- /dev/null +++ b/pkg/api/virtlet.k8s/v1/virtletconfig.go @@ -0,0 +1,91 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or ≈git-agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VirtletConfig denotes a configuration for VirtletManager. +type VirtletConfig struct { + // FdServerSocketPath specifies the path to fdServer socket. + FDServerSocketPath *string `json:"fdServerSocketPath,omitempty"` + // DatabasePath specifies the path to Virtlet database. + DatabasePath *string `json:"databasePath,omitempty"` + // DownloadProtocol specifies the download protocol to use. + // It defaults to "https". + DownloadProtocol *string `json:"downloadProtocol,omitempty"` + // ImageDir specifies the image store directory. + ImageDir *string `json:"imageDir,omitempty"` + // ImageTranslationConfigsDir specifies the directory with + // image translation configuration files. Empty string means + // such directory is not used. + ImageTranslationConfigsDir *string `json:"imageTranslationConfigsDir,omitempty"` + // SkipImageTranslation disables image translations. + SkipImageTranslation *bool `json:"skipImageTranslation,omitempty"` + // LibvirtURI specifies the libvirt connnection URI. + LibvirtURI *string `json:"libvirtURI,omitempty"` + // RawDevices specifies a comma-separated list of raw device + // glob patterns which VMs can access. + RawDevices *string `json:"rawDevices,omitempty"` + // CRISocketPath specifies the socket path for the gRPC endpoint. + CRISocketPath *string `json:"criSocketPath,omitempty"` + // DisableLogging disables the streaming server + DisableLogging *bool `json:"disableLogging,omitempty"` + // True if KVM should be disabled. + DisableKVM *bool `json:"disableKVM,omitempty"` + // True if SR-IOV support should be enabled. + EnableSriov *bool `json:"enableSriov,omitempty"` + // CNIPluginDir specifies the location of CNI configurations. + CNIPluginDir *string `json:"cniPluginDir,omitempty"` + // CNIConfigDir specifies the location of CNI configurations. + CNIConfigDir *string `json:"cniConfigDir,omitempty"` + // CalicoSubnetSize specifies the size of Calico subnetwork. + CalicoSubnetSize *int `json:"calicoSubnetSize,omitempty"` + // EnableRegexpImageTranslation is true if regexp-based image + // translations are enabled. + EnableRegexpImageTranslation *bool `json:"enableRegexpImageTranslation,omitempty"` + // LogLevel specifies the log level to use + LogLevel *int `json:"logLevel,omitempty"` +} + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VirtletConfigMapping specifies the mapping of node names or labels +// to Virtlet configs. +type VirtletConfigMapping struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + // Node name to match. + NodeName string `json:"nodeName,omitempty"` + // Node label to match. + Label string `json:"label,omitempty"` + // VirtletConfig to apply. + Config *VirtletConfig `json:"config,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VirtletConfigMappingList lists the mappings between node names or +// labels and Virtlet configs. +type VirtletConfigMappingList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata"` + Items []VirtletConfigMapping `json:"mappings,omitempty"` +} diff --git a/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go b/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..bbd9e2255 --- /dev/null +++ b/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go @@ -0,0 +1,439 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageTranslation) DeepCopyInto(out *ImageTranslation) { + *out = *in + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]TranslationRule, len(*in)) + copy(*out, *in) + } + if in.Transports != nil { + in, out := &in.Transports, &out.Transports + *out = make(map[string]TransportProfile, len(*in)) + for key, val := range *in { + newVal := new(TransportProfile) + val.DeepCopyInto(newVal) + (*out)[key] = *newVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageTranslation. +func (in *ImageTranslation) DeepCopy() *ImageTranslation { + if in == nil { + return nil + } + out := new(ImageTranslation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSCertificate) DeepCopyInto(out *TLSCertificate) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCertificate. +func (in *TLSCertificate) DeepCopy() *TLSCertificate { + if in == nil { + return nil + } + out := new(TLSCertificate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { + *out = *in + if in.Certificates != nil { + in, out := &in.Certificates, &out.Certificates + *out = make([]TLSCertificate, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. +func (in *TLSConfig) DeepCopy() *TLSConfig { + if in == nil { + return nil + } + out := new(TLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TranslationRule) DeepCopyInto(out *TranslationRule) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TranslationRule. +func (in *TranslationRule) DeepCopy() *TranslationRule { + if in == nil { + return nil + } + out := new(TranslationRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TransportProfile) DeepCopyInto(out *TransportProfile) { + *out = *in + if in.MaxRedirects != nil { + in, out := &in.MaxRedirects, &out.MaxRedirects + if *in == nil { + *out = nil + } else { + *out = new(int) + **out = **in + } + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + if *in == nil { + *out = nil + } else { + *out = new(TLSConfig) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TransportProfile. +func (in *TransportProfile) DeepCopy() *TransportProfile { + if in == nil { + return nil + } + out := new(TransportProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtletConfig) DeepCopyInto(out *VirtletConfig) { + *out = *in + if in.FDServerSocketPath != nil { + in, out := &in.FDServerSocketPath, &out.FDServerSocketPath + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.DatabasePath != nil { + in, out := &in.DatabasePath, &out.DatabasePath + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.DownloadProtocol != nil { + in, out := &in.DownloadProtocol, &out.DownloadProtocol + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.ImageDir != nil { + in, out := &in.ImageDir, &out.ImageDir + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.ImageTranslationConfigsDir != nil { + in, out := &in.ImageTranslationConfigsDir, &out.ImageTranslationConfigsDir + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.SkipImageTranslation != nil { + in, out := &in.SkipImageTranslation, &out.SkipImageTranslation + if *in == nil { + *out = nil + } else { + *out = new(bool) + **out = **in + } + } + if in.LibvirtURI != nil { + in, out := &in.LibvirtURI, &out.LibvirtURI + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.RawDevices != nil { + in, out := &in.RawDevices, &out.RawDevices + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.CRISocketPath != nil { + in, out := &in.CRISocketPath, &out.CRISocketPath + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.DisableLogging != nil { + in, out := &in.DisableLogging, &out.DisableLogging + if *in == nil { + *out = nil + } else { + *out = new(bool) + **out = **in + } + } + if in.DisableKVM != nil { + in, out := &in.DisableKVM, &out.DisableKVM + if *in == nil { + *out = nil + } else { + *out = new(bool) + **out = **in + } + } + if in.EnableSriov != nil { + in, out := &in.EnableSriov, &out.EnableSriov + if *in == nil { + *out = nil + } else { + *out = new(bool) + **out = **in + } + } + if in.CNIPluginDir != nil { + in, out := &in.CNIPluginDir, &out.CNIPluginDir + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.CNIConfigDir != nil { + in, out := &in.CNIConfigDir, &out.CNIConfigDir + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + if in.CalicoSubnetSize != nil { + in, out := &in.CalicoSubnetSize, &out.CalicoSubnetSize + if *in == nil { + *out = nil + } else { + *out = new(int) + **out = **in + } + } + if in.EnableRegexpImageTranslation != nil { + in, out := &in.EnableRegexpImageTranslation, &out.EnableRegexpImageTranslation + if *in == nil { + *out = nil + } else { + *out = new(bool) + **out = **in + } + } + if in.LogLevel != nil { + in, out := &in.LogLevel, &out.LogLevel + if *in == nil { + *out = nil + } else { + *out = new(int) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtletConfig. +func (in *VirtletConfig) DeepCopy() *VirtletConfig { + if in == nil { + return nil + } + out := new(VirtletConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtletConfigMapping) DeepCopyInto(out *VirtletConfigMapping) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Config != nil { + in, out := &in.Config, &out.Config + if *in == nil { + *out = nil + } else { + *out = new(VirtletConfig) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtletConfigMapping. +func (in *VirtletConfigMapping) DeepCopy() *VirtletConfigMapping { + if in == nil { + return nil + } + out := new(VirtletConfigMapping) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtletConfigMapping) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtletConfigMappingList) DeepCopyInto(out *VirtletConfigMappingList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VirtletConfigMapping, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtletConfigMappingList. +func (in *VirtletConfigMappingList) DeepCopy() *VirtletConfigMappingList { + if in == nil { + return nil + } + out := new(VirtletConfigMappingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtletConfigMappingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtletImageMapping) DeepCopyInto(out *VirtletImageMapping) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtletImageMapping. +func (in *VirtletImageMapping) DeepCopy() *VirtletImageMapping { + if in == nil { + return nil + } + out := new(VirtletImageMapping) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtletImageMapping) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtletImageMappingList) DeepCopyInto(out *VirtletImageMappingList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VirtletImageMapping, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtletImageMappingList. +func (in *VirtletImageMappingList) DeepCopy() *VirtletImageMappingList { + if in == nil { + return nil + } + out := new(VirtletImageMappingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtletImageMappingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go new file mode 100644 index 000000000..63e89984a --- /dev/null +++ b/pkg/client/clientset/versioned/clientset.go @@ -0,0 +1,100 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + glog "github.com/golang/glog" + virtletv1 "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/typed/virtlet.k8s/v1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + VirtletV1() virtletv1.VirtletV1Interface + // Deprecated: please explicitly pick a version if possible. + Virtlet() virtletv1.VirtletV1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + virtletV1 *virtletv1.VirtletV1Client +} + +// VirtletV1 retrieves the VirtletV1Client +func (c *Clientset) VirtletV1() virtletv1.VirtletV1Interface { + return c.virtletV1 +} + +// Deprecated: Virtlet retrieves the default version of VirtletClient. +// Please explicitly pick a version. +func (c *Clientset) Virtlet() virtletv1.VirtletV1Interface { + return c.virtletV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.virtletV1, err = virtletv1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + glog.Errorf("failed to create the DiscoveryClient: %v", err) + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.virtletV1 = virtletv1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.virtletV1 = virtletv1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/client/clientset/versioned/doc.go b/pkg/client/clientset/versioned/doc.go new file mode 100644 index 000000000..eee7b58e4 --- /dev/null +++ b/pkg/client/clientset/versioned/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..3a6fd0426 --- /dev/null +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,81 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + clientset "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + virtletv1 "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/typed/virtlet.k8s/v1" + fakevirtletv1 "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + fakePtr := testing.Fake{} + fakePtr.AddReactor("*", "*", testing.ObjectReaction(o)) + fakePtr.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return &Clientset{fakePtr, &fakediscovery.FakeDiscovery{Fake: &fakePtr}} +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// VirtletV1 retrieves the VirtletV1Client +func (c *Clientset) VirtletV1() virtletv1.VirtletV1Interface { + return &fakevirtletv1.FakeVirtletV1{Fake: &c.Fake} +} + +// Virtlet retrieves the VirtletV1Client +func (c *Clientset) Virtlet() virtletv1.VirtletV1Interface { + return &fakevirtletv1.FakeVirtletV1{Fake: &c.Fake} +} diff --git a/pkg/client/clientset/versioned/fake/doc.go b/pkg/client/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..45b272fc0 --- /dev/null +++ b/pkg/client/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go new file mode 100644 index 000000000..0686ecd81 --- /dev/null +++ b/pkg/client/clientset/versioned/fake/register.go @@ -0,0 +1,54 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + virtletv1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + AddToScheme(scheme) +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +func AddToScheme(scheme *runtime.Scheme) { + virtletv1.AddToScheme(scheme) +} diff --git a/pkg/client/clientset/versioned/scheme/doc.go b/pkg/client/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..2e3c67834 --- /dev/null +++ b/pkg/client/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..e9c16803f --- /dev/null +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -0,0 +1,54 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + virtletv1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + AddToScheme(Scheme) +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +func AddToScheme(scheme *runtime.Scheme) { + virtletv1.AddToScheme(scheme) +} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/doc.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/doc.go new file mode 100644 index 000000000..9fc1ba483 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/doc.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/doc.go new file mode 100644 index 000000000..51b6d2efc --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtlet.k8s_client.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtlet.k8s_client.go new file mode 100644 index 000000000..7efb52820 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtlet.k8s_client.go @@ -0,0 +1,44 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/typed/virtlet.k8s/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeVirtletV1 struct { + *testing.Fake +} + +func (c *FakeVirtletV1) VirtletConfigMappings(namespace string) v1.VirtletConfigMappingInterface { + return &FakeVirtletConfigMappings{c, namespace} +} + +func (c *FakeVirtletV1) VirtletImageMappings(namespace string) v1.VirtletImageMappingInterface { + return &FakeVirtletImageMappings{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeVirtletV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletconfigmapping.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletconfigmapping.go new file mode 100644 index 000000000..c550fed2d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletconfigmapping.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + virtlet_k8s_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeVirtletConfigMappings implements VirtletConfigMappingInterface +type FakeVirtletConfigMappings struct { + Fake *FakeVirtletV1 + ns string +} + +var virtletconfigmappingsResource = schema.GroupVersionResource{Group: "virtlet.k8s", Version: "v1", Resource: "virtletconfigmappings"} + +var virtletconfigmappingsKind = schema.GroupVersionKind{Group: "virtlet.k8s", Version: "v1", Kind: "VirtletConfigMapping"} + +// Get takes name of the virtletConfigMapping, and returns the corresponding virtletConfigMapping object, and an error if there is any. +func (c *FakeVirtletConfigMappings) Get(name string, options v1.GetOptions) (result *virtlet_k8s_v1.VirtletConfigMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(virtletconfigmappingsResource, c.ns, name), &virtlet_k8s_v1.VirtletConfigMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletConfigMapping), err +} + +// List takes label and field selectors, and returns the list of VirtletConfigMappings that match those selectors. +func (c *FakeVirtletConfigMappings) List(opts v1.ListOptions) (result *virtlet_k8s_v1.VirtletConfigMappingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(virtletconfigmappingsResource, virtletconfigmappingsKind, c.ns, opts), &virtlet_k8s_v1.VirtletConfigMappingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &virtlet_k8s_v1.VirtletConfigMappingList{} + for _, item := range obj.(*virtlet_k8s_v1.VirtletConfigMappingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested virtletConfigMappings. +func (c *FakeVirtletConfigMappings) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(virtletconfigmappingsResource, c.ns, opts)) + +} + +// Create takes the representation of a virtletConfigMapping and creates it. Returns the server's representation of the virtletConfigMapping, and an error, if there is any. +func (c *FakeVirtletConfigMappings) Create(virtletConfigMapping *virtlet_k8s_v1.VirtletConfigMapping) (result *virtlet_k8s_v1.VirtletConfigMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(virtletconfigmappingsResource, c.ns, virtletConfigMapping), &virtlet_k8s_v1.VirtletConfigMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletConfigMapping), err +} + +// Update takes the representation of a virtletConfigMapping and updates it. Returns the server's representation of the virtletConfigMapping, and an error, if there is any. +func (c *FakeVirtletConfigMappings) Update(virtletConfigMapping *virtlet_k8s_v1.VirtletConfigMapping) (result *virtlet_k8s_v1.VirtletConfigMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(virtletconfigmappingsResource, c.ns, virtletConfigMapping), &virtlet_k8s_v1.VirtletConfigMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletConfigMapping), err +} + +// Delete takes name of the virtletConfigMapping and deletes it. Returns an error if one occurs. +func (c *FakeVirtletConfigMappings) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(virtletconfigmappingsResource, c.ns, name), &virtlet_k8s_v1.VirtletConfigMapping{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVirtletConfigMappings) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(virtletconfigmappingsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &virtlet_k8s_v1.VirtletConfigMappingList{}) + return err +} + +// Patch applies the patch and returns the patched virtletConfigMapping. +func (c *FakeVirtletConfigMappings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *virtlet_k8s_v1.VirtletConfigMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(virtletconfigmappingsResource, c.ns, name, data, subresources...), &virtlet_k8s_v1.VirtletConfigMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletConfigMapping), err +} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletimagemapping.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletimagemapping.go new file mode 100644 index 000000000..32e8d167a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/fake/fake_virtletimagemapping.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + virtlet_k8s_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeVirtletImageMappings implements VirtletImageMappingInterface +type FakeVirtletImageMappings struct { + Fake *FakeVirtletV1 + ns string +} + +var virtletimagemappingsResource = schema.GroupVersionResource{Group: "virtlet.k8s", Version: "v1", Resource: "virtletimagemappings"} + +var virtletimagemappingsKind = schema.GroupVersionKind{Group: "virtlet.k8s", Version: "v1", Kind: "VirtletImageMapping"} + +// Get takes name of the virtletImageMapping, and returns the corresponding virtletImageMapping object, and an error if there is any. +func (c *FakeVirtletImageMappings) Get(name string, options v1.GetOptions) (result *virtlet_k8s_v1.VirtletImageMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(virtletimagemappingsResource, c.ns, name), &virtlet_k8s_v1.VirtletImageMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletImageMapping), err +} + +// List takes label and field selectors, and returns the list of VirtletImageMappings that match those selectors. +func (c *FakeVirtletImageMappings) List(opts v1.ListOptions) (result *virtlet_k8s_v1.VirtletImageMappingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(virtletimagemappingsResource, virtletimagemappingsKind, c.ns, opts), &virtlet_k8s_v1.VirtletImageMappingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &virtlet_k8s_v1.VirtletImageMappingList{} + for _, item := range obj.(*virtlet_k8s_v1.VirtletImageMappingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested virtletImageMappings. +func (c *FakeVirtletImageMappings) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(virtletimagemappingsResource, c.ns, opts)) + +} + +// Create takes the representation of a virtletImageMapping and creates it. Returns the server's representation of the virtletImageMapping, and an error, if there is any. +func (c *FakeVirtletImageMappings) Create(virtletImageMapping *virtlet_k8s_v1.VirtletImageMapping) (result *virtlet_k8s_v1.VirtletImageMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(virtletimagemappingsResource, c.ns, virtletImageMapping), &virtlet_k8s_v1.VirtletImageMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletImageMapping), err +} + +// Update takes the representation of a virtletImageMapping and updates it. Returns the server's representation of the virtletImageMapping, and an error, if there is any. +func (c *FakeVirtletImageMappings) Update(virtletImageMapping *virtlet_k8s_v1.VirtletImageMapping) (result *virtlet_k8s_v1.VirtletImageMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(virtletimagemappingsResource, c.ns, virtletImageMapping), &virtlet_k8s_v1.VirtletImageMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletImageMapping), err +} + +// Delete takes name of the virtletImageMapping and deletes it. Returns an error if one occurs. +func (c *FakeVirtletImageMappings) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(virtletimagemappingsResource, c.ns, name), &virtlet_k8s_v1.VirtletImageMapping{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVirtletImageMappings) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(virtletimagemappingsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &virtlet_k8s_v1.VirtletImageMappingList{}) + return err +} + +// Patch applies the patch and returns the patched virtletImageMapping. +func (c *FakeVirtletImageMappings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *virtlet_k8s_v1.VirtletImageMapping, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(virtletimagemappingsResource, c.ns, name, data, subresources...), &virtlet_k8s_v1.VirtletImageMapping{}) + + if obj == nil { + return nil, err + } + return obj.(*virtlet_k8s_v1.VirtletImageMapping), err +} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/generated_expansion.go new file mode 100644 index 000000000..7d0da96d3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type VirtletConfigMappingExpansion interface{} + +type VirtletImageMappingExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtlet.k8s_client.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtlet.k8s_client.go new file mode 100644 index 000000000..be033b4fc --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtlet.k8s_client.go @@ -0,0 +1,95 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type VirtletV1Interface interface { + RESTClient() rest.Interface + VirtletConfigMappingsGetter + VirtletImageMappingsGetter +} + +// VirtletV1Client is used to interact with features provided by the virtlet.k8s group. +type VirtletV1Client struct { + restClient rest.Interface +} + +func (c *VirtletV1Client) VirtletConfigMappings(namespace string) VirtletConfigMappingInterface { + return newVirtletConfigMappings(c, namespace) +} + +func (c *VirtletV1Client) VirtletImageMappings(namespace string) VirtletImageMappingInterface { + return newVirtletImageMappings(c, namespace) +} + +// NewForConfig creates a new VirtletV1Client for the given config. +func NewForConfig(c *rest.Config) (*VirtletV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &VirtletV1Client{client}, nil +} + +// NewForConfigOrDie creates a new VirtletV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *VirtletV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new VirtletV1Client for the given RESTClient. +func New(c rest.Interface) *VirtletV1Client { + return &VirtletV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *VirtletV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletconfigmapping.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletconfigmapping.go new file mode 100644 index 000000000..3c017d94b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletconfigmapping.go @@ -0,0 +1,157 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + scheme "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/scheme" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// VirtletConfigMappingsGetter has a method to return a VirtletConfigMappingInterface. +// A group's client should implement this interface. +type VirtletConfigMappingsGetter interface { + VirtletConfigMappings(namespace string) VirtletConfigMappingInterface +} + +// VirtletConfigMappingInterface has methods to work with VirtletConfigMapping resources. +type VirtletConfigMappingInterface interface { + Create(*v1.VirtletConfigMapping) (*v1.VirtletConfigMapping, error) + Update(*v1.VirtletConfigMapping) (*v1.VirtletConfigMapping, error) + Delete(name string, options *meta_v1.DeleteOptions) error + DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error + Get(name string, options meta_v1.GetOptions) (*v1.VirtletConfigMapping, error) + List(opts meta_v1.ListOptions) (*v1.VirtletConfigMappingList, error) + Watch(opts meta_v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VirtletConfigMapping, err error) + VirtletConfigMappingExpansion +} + +// virtletConfigMappings implements VirtletConfigMappingInterface +type virtletConfigMappings struct { + client rest.Interface + ns string +} + +// newVirtletConfigMappings returns a VirtletConfigMappings +func newVirtletConfigMappings(c *VirtletV1Client, namespace string) *virtletConfigMappings { + return &virtletConfigMappings{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the virtletConfigMapping, and returns the corresponding virtletConfigMapping object, and an error if there is any. +func (c *virtletConfigMappings) Get(name string, options meta_v1.GetOptions) (result *v1.VirtletConfigMapping, err error) { + result = &v1.VirtletConfigMapping{} + err = c.client.Get(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of VirtletConfigMappings that match those selectors. +func (c *virtletConfigMappings) List(opts meta_v1.ListOptions) (result *v1.VirtletConfigMappingList, err error) { + result = &v1.VirtletConfigMappingList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested virtletConfigMappings. +func (c *virtletConfigMappings) Watch(opts meta_v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a virtletConfigMapping and creates it. Returns the server's representation of the virtletConfigMapping, and an error, if there is any. +func (c *virtletConfigMappings) Create(virtletConfigMapping *v1.VirtletConfigMapping) (result *v1.VirtletConfigMapping, err error) { + result = &v1.VirtletConfigMapping{} + err = c.client.Post(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + Body(virtletConfigMapping). + Do(). + Into(result) + return +} + +// Update takes the representation of a virtletConfigMapping and updates it. Returns the server's representation of the virtletConfigMapping, and an error, if there is any. +func (c *virtletConfigMappings) Update(virtletConfigMapping *v1.VirtletConfigMapping) (result *v1.VirtletConfigMapping, err error) { + result = &v1.VirtletConfigMapping{} + err = c.client.Put(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + Name(virtletConfigMapping.Name). + Body(virtletConfigMapping). + Do(). + Into(result) + return +} + +// Delete takes name of the virtletConfigMapping and deletes it. Returns an error if one occurs. +func (c *virtletConfigMappings) Delete(name string, options *meta_v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *virtletConfigMappings) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("virtletconfigmappings"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched virtletConfigMapping. +func (c *virtletConfigMappings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VirtletConfigMapping, err error) { + result = &v1.VirtletConfigMapping{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("virtletconfigmappings"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletimagemapping.go b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletimagemapping.go new file mode 100644 index 000000000..c4829f1a8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/virtlet.k8s/v1/virtletimagemapping.go @@ -0,0 +1,157 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + scheme "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/scheme" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// VirtletImageMappingsGetter has a method to return a VirtletImageMappingInterface. +// A group's client should implement this interface. +type VirtletImageMappingsGetter interface { + VirtletImageMappings(namespace string) VirtletImageMappingInterface +} + +// VirtletImageMappingInterface has methods to work with VirtletImageMapping resources. +type VirtletImageMappingInterface interface { + Create(*v1.VirtletImageMapping) (*v1.VirtletImageMapping, error) + Update(*v1.VirtletImageMapping) (*v1.VirtletImageMapping, error) + Delete(name string, options *meta_v1.DeleteOptions) error + DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error + Get(name string, options meta_v1.GetOptions) (*v1.VirtletImageMapping, error) + List(opts meta_v1.ListOptions) (*v1.VirtletImageMappingList, error) + Watch(opts meta_v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VirtletImageMapping, err error) + VirtletImageMappingExpansion +} + +// virtletImageMappings implements VirtletImageMappingInterface +type virtletImageMappings struct { + client rest.Interface + ns string +} + +// newVirtletImageMappings returns a VirtletImageMappings +func newVirtletImageMappings(c *VirtletV1Client, namespace string) *virtletImageMappings { + return &virtletImageMappings{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the virtletImageMapping, and returns the corresponding virtletImageMapping object, and an error if there is any. +func (c *virtletImageMappings) Get(name string, options meta_v1.GetOptions) (result *v1.VirtletImageMapping, err error) { + result = &v1.VirtletImageMapping{} + err = c.client.Get(). + Namespace(c.ns). + Resource("virtletimagemappings"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of VirtletImageMappings that match those selectors. +func (c *virtletImageMappings) List(opts meta_v1.ListOptions) (result *v1.VirtletImageMappingList, err error) { + result = &v1.VirtletImageMappingList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("virtletimagemappings"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested virtletImageMappings. +func (c *virtletImageMappings) Watch(opts meta_v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("virtletimagemappings"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a virtletImageMapping and creates it. Returns the server's representation of the virtletImageMapping, and an error, if there is any. +func (c *virtletImageMappings) Create(virtletImageMapping *v1.VirtletImageMapping) (result *v1.VirtletImageMapping, err error) { + result = &v1.VirtletImageMapping{} + err = c.client.Post(). + Namespace(c.ns). + Resource("virtletimagemappings"). + Body(virtletImageMapping). + Do(). + Into(result) + return +} + +// Update takes the representation of a virtletImageMapping and updates it. Returns the server's representation of the virtletImageMapping, and an error, if there is any. +func (c *virtletImageMappings) Update(virtletImageMapping *v1.VirtletImageMapping) (result *v1.VirtletImageMapping, err error) { + result = &v1.VirtletImageMapping{} + err = c.client.Put(). + Namespace(c.ns). + Resource("virtletimagemappings"). + Name(virtletImageMapping.Name). + Body(virtletImageMapping). + Do(). + Into(result) + return +} + +// Delete takes name of the virtletImageMapping and deletes it. Returns an error if one occurs. +func (c *virtletImageMappings) Delete(name string, options *meta_v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("virtletimagemappings"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *virtletImageMappings) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("virtletimagemappings"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched virtletImageMapping. +func (c *virtletImageMappings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VirtletImageMapping, err error) { + result = &v1.VirtletImageMapping{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("virtletimagemappings"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go new file mode 100644 index 000000000..8f8ae8b19 --- /dev/null +++ b/pkg/client/informers/externalversions/factory.go @@ -0,0 +1,131 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + internalinterfaces "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/internalinterfaces" + virtlet_k8s "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/virtlet.k8s" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewFilteredSharedInformerFactory(client, defaultResync, v1.NamespaceAll, nil) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return &sharedInformerFactory{ + client: client, + namespace: namespace, + tweakListOptions: tweakListOptions, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + } +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + informer = newFunc(f.client, f.defaultResync) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Virtlet() virtlet_k8s.Interface +} + +func (f *sharedInformerFactory) Virtlet() virtlet_k8s.Interface { + return virtlet_k8s.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go new file mode 100644 index 000000000..266f1d837 --- /dev/null +++ b/pkg/client/informers/externalversions/generic.go @@ -0,0 +1,64 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=virtlet.k8s, Version=v1 + case v1.SchemeGroupVersion.WithResource("virtletconfigmappings"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Virtlet().V1().VirtletConfigMappings().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("virtletimagemappings"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Virtlet().V1().VirtletImageMappings().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..7688ea543 --- /dev/null +++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,38 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/client/informers/externalversions/virtlet.k8s/interface.go b/pkg/client/informers/externalversions/virtlet.k8s/interface.go new file mode 100644 index 000000000..83b8599c1 --- /dev/null +++ b/pkg/client/informers/externalversions/virtlet.k8s/interface.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package virtlet + +import ( + internalinterfaces "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/virtlet.k8s/v1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/virtlet.k8s/v1/interface.go b/pkg/client/informers/externalversions/virtlet.k8s/v1/interface.go new file mode 100644 index 000000000..df1069bab --- /dev/null +++ b/pkg/client/informers/externalversions/virtlet.k8s/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // VirtletConfigMappings returns a VirtletConfigMappingInformer. + VirtletConfigMappings() VirtletConfigMappingInformer + // VirtletImageMappings returns a VirtletImageMappingInformer. + VirtletImageMappings() VirtletImageMappingInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// VirtletConfigMappings returns a VirtletConfigMappingInformer. +func (v *version) VirtletConfigMappings() VirtletConfigMappingInformer { + return &virtletConfigMappingInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// VirtletImageMappings returns a VirtletImageMappingInformer. +func (v *version) VirtletImageMappings() VirtletImageMappingInformer { + return &virtletImageMappingInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/virtlet.k8s/v1/virtletconfigmapping.go b/pkg/client/informers/externalversions/virtlet.k8s/v1/virtletconfigmapping.go new file mode 100644 index 000000000..25c1b3044 --- /dev/null +++ b/pkg/client/informers/externalversions/virtlet.k8s/v1/virtletconfigmapping.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + virtlet_k8s_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + versioned "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + internalinterfaces "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/Mirantis/virtlet/pkg/client/listers/virtlet.k8s/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VirtletConfigMappingInformer provides access to a shared informer and lister for +// VirtletConfigMappings. +type VirtletConfigMappingInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.VirtletConfigMappingLister +} + +type virtletConfigMappingInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewVirtletConfigMappingInformer constructs a new informer for VirtletConfigMapping type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVirtletConfigMappingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVirtletConfigMappingInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredVirtletConfigMappingInformer constructs a new informer for VirtletConfigMapping type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVirtletConfigMappingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtletV1().VirtletConfigMappings(namespace).List(options) + }, + WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtletV1().VirtletConfigMappings(namespace).Watch(options) + }, + }, + &virtlet_k8s_v1.VirtletConfigMapping{}, + resyncPeriod, + indexers, + ) +} + +func (f *virtletConfigMappingInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVirtletConfigMappingInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *virtletConfigMappingInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&virtlet_k8s_v1.VirtletConfigMapping{}, f.defaultInformer) +} + +func (f *virtletConfigMappingInformer) Lister() v1.VirtletConfigMappingLister { + return v1.NewVirtletConfigMappingLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/virtlet.k8s/v1/virtletimagemapping.go b/pkg/client/informers/externalversions/virtlet.k8s/v1/virtletimagemapping.go new file mode 100644 index 000000000..8b19fa756 --- /dev/null +++ b/pkg/client/informers/externalversions/virtlet.k8s/v1/virtletimagemapping.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + virtlet_k8s_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + versioned "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + internalinterfaces "github.com/Mirantis/virtlet/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/Mirantis/virtlet/pkg/client/listers/virtlet.k8s/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VirtletImageMappingInformer provides access to a shared informer and lister for +// VirtletImageMappings. +type VirtletImageMappingInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.VirtletImageMappingLister +} + +type virtletImageMappingInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewVirtletImageMappingInformer constructs a new informer for VirtletImageMapping type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVirtletImageMappingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVirtletImageMappingInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredVirtletImageMappingInformer constructs a new informer for VirtletImageMapping type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVirtletImageMappingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtletV1().VirtletImageMappings(namespace).List(options) + }, + WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtletV1().VirtletImageMappings(namespace).Watch(options) + }, + }, + &virtlet_k8s_v1.VirtletImageMapping{}, + resyncPeriod, + indexers, + ) +} + +func (f *virtletImageMappingInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVirtletImageMappingInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *virtletImageMappingInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&virtlet_k8s_v1.VirtletImageMapping{}, f.defaultInformer) +} + +func (f *virtletImageMappingInformer) Lister() v1.VirtletImageMappingLister { + return v1.NewVirtletImageMappingLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/virtlet.k8s/v1/expansion_generated.go b/pkg/client/listers/virtlet.k8s/v1/expansion_generated.go new file mode 100644 index 000000000..cbce69934 --- /dev/null +++ b/pkg/client/listers/virtlet.k8s/v1/expansion_generated.go @@ -0,0 +1,35 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// VirtletConfigMappingListerExpansion allows custom methods to be added to +// VirtletConfigMappingLister. +type VirtletConfigMappingListerExpansion interface{} + +// VirtletConfigMappingNamespaceListerExpansion allows custom methods to be added to +// VirtletConfigMappingNamespaceLister. +type VirtletConfigMappingNamespaceListerExpansion interface{} + +// VirtletImageMappingListerExpansion allows custom methods to be added to +// VirtletImageMappingLister. +type VirtletImageMappingListerExpansion interface{} + +// VirtletImageMappingNamespaceListerExpansion allows custom methods to be added to +// VirtletImageMappingNamespaceLister. +type VirtletImageMappingNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/virtlet.k8s/v1/virtletconfigmapping.go b/pkg/client/listers/virtlet.k8s/v1/virtletconfigmapping.go new file mode 100644 index 000000000..016b1f7ea --- /dev/null +++ b/pkg/client/listers/virtlet.k8s/v1/virtletconfigmapping.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// VirtletConfigMappingLister helps list VirtletConfigMappings. +type VirtletConfigMappingLister interface { + // List lists all VirtletConfigMappings in the indexer. + List(selector labels.Selector) (ret []*v1.VirtletConfigMapping, err error) + // VirtletConfigMappings returns an object that can list and get VirtletConfigMappings. + VirtletConfigMappings(namespace string) VirtletConfigMappingNamespaceLister + VirtletConfigMappingListerExpansion +} + +// virtletConfigMappingLister implements the VirtletConfigMappingLister interface. +type virtletConfigMappingLister struct { + indexer cache.Indexer +} + +// NewVirtletConfigMappingLister returns a new VirtletConfigMappingLister. +func NewVirtletConfigMappingLister(indexer cache.Indexer) VirtletConfigMappingLister { + return &virtletConfigMappingLister{indexer: indexer} +} + +// List lists all VirtletConfigMappings in the indexer. +func (s *virtletConfigMappingLister) List(selector labels.Selector) (ret []*v1.VirtletConfigMapping, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VirtletConfigMapping)) + }) + return ret, err +} + +// VirtletConfigMappings returns an object that can list and get VirtletConfigMappings. +func (s *virtletConfigMappingLister) VirtletConfigMappings(namespace string) VirtletConfigMappingNamespaceLister { + return virtletConfigMappingNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// VirtletConfigMappingNamespaceLister helps list and get VirtletConfigMappings. +type VirtletConfigMappingNamespaceLister interface { + // List lists all VirtletConfigMappings in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.VirtletConfigMapping, err error) + // Get retrieves the VirtletConfigMapping from the indexer for a given namespace and name. + Get(name string) (*v1.VirtletConfigMapping, error) + VirtletConfigMappingNamespaceListerExpansion +} + +// virtletConfigMappingNamespaceLister implements the VirtletConfigMappingNamespaceLister +// interface. +type virtletConfigMappingNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all VirtletConfigMappings in the indexer for a given namespace. +func (s virtletConfigMappingNamespaceLister) List(selector labels.Selector) (ret []*v1.VirtletConfigMapping, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VirtletConfigMapping)) + }) + return ret, err +} + +// Get retrieves the VirtletConfigMapping from the indexer for a given namespace and name. +func (s virtletConfigMappingNamespaceLister) Get(name string) (*v1.VirtletConfigMapping, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("virtletconfigmapping"), name) + } + return obj.(*v1.VirtletConfigMapping), nil +} diff --git a/pkg/client/listers/virtlet.k8s/v1/virtletimagemapping.go b/pkg/client/listers/virtlet.k8s/v1/virtletimagemapping.go new file mode 100644 index 000000000..77fcf690f --- /dev/null +++ b/pkg/client/listers/virtlet.k8s/v1/virtletimagemapping.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// VirtletImageMappingLister helps list VirtletImageMappings. +type VirtletImageMappingLister interface { + // List lists all VirtletImageMappings in the indexer. + List(selector labels.Selector) (ret []*v1.VirtletImageMapping, err error) + // VirtletImageMappings returns an object that can list and get VirtletImageMappings. + VirtletImageMappings(namespace string) VirtletImageMappingNamespaceLister + VirtletImageMappingListerExpansion +} + +// virtletImageMappingLister implements the VirtletImageMappingLister interface. +type virtletImageMappingLister struct { + indexer cache.Indexer +} + +// NewVirtletImageMappingLister returns a new VirtletImageMappingLister. +func NewVirtletImageMappingLister(indexer cache.Indexer) VirtletImageMappingLister { + return &virtletImageMappingLister{indexer: indexer} +} + +// List lists all VirtletImageMappings in the indexer. +func (s *virtletImageMappingLister) List(selector labels.Selector) (ret []*v1.VirtletImageMapping, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VirtletImageMapping)) + }) + return ret, err +} + +// VirtletImageMappings returns an object that can list and get VirtletImageMappings. +func (s *virtletImageMappingLister) VirtletImageMappings(namespace string) VirtletImageMappingNamespaceLister { + return virtletImageMappingNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// VirtletImageMappingNamespaceLister helps list and get VirtletImageMappings. +type VirtletImageMappingNamespaceLister interface { + // List lists all VirtletImageMappings in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.VirtletImageMapping, err error) + // Get retrieves the VirtletImageMapping from the indexer for a given namespace and name. + Get(name string) (*v1.VirtletImageMapping, error) + VirtletImageMappingNamespaceListerExpansion +} + +// virtletImageMappingNamespaceLister implements the VirtletImageMappingNamespaceLister +// interface. +type virtletImageMappingNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all VirtletImageMappings in the indexer for a given namespace. +func (s virtletImageMappingNamespaceLister) List(selector labels.Selector) (ret []*v1.VirtletImageMapping, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VirtletImageMapping)) + }) + return ret, err +} + +// Get retrieves the VirtletImageMapping from the indexer for a given namespace and name. +func (s virtletImageMappingNamespaceLister) Get(name string) (*v1.VirtletImageMapping, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("virtletimagemapping"), name) + } + return obj.(*v1.VirtletImageMapping), nil +} diff --git a/pkg/config/TestConfigForNode__mapping_by_node_labels.out.yaml b/pkg/config/TestConfigForNode__mapping_by_node_labels.out.yaml new file mode 100755 index 000000000..19dce3550 --- /dev/null +++ b/pkg/config/TestConfigForNode__mapping_by_node_labels.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 22 +cniConfigDir: /some/cni/conf/dir +cniPluginDir: /some/cni/bin/dir +criSocketPath: /some/cri.sock +databasePath: /some/file.db +disableKVM: true +disableLogging: true +downloadProtocol: http +enableRegexpImageTranslation: false +enableSriov: true +fdServerSocketPath: /some/fd/server.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /some/translation/dir +libvirtURI: qemu:///foobar +logLevel: 3 +rawDevices: sd* +skipImageTranslation: false diff --git a/pkg/config/TestConfigForNode__mapping_by_node_labels__no_match_.out.yaml b/pkg/config/TestConfigForNode__mapping_by_node_labels__no_match_.out.yaml new file mode 100755 index 000000000..75883e0b1 --- /dev/null +++ b/pkg/config/TestConfigForNode__mapping_by_node_labels__no_match_.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: false +disableLogging: false +downloadProtocol: https +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: loop* +skipImageTranslation: false diff --git a/pkg/config/TestConfigForNode__mapping_by_node_name.out.yaml b/pkg/config/TestConfigForNode__mapping_by_node_name.out.yaml new file mode 100755 index 000000000..19dce3550 --- /dev/null +++ b/pkg/config/TestConfigForNode__mapping_by_node_name.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 22 +cniConfigDir: /some/cni/conf/dir +cniPluginDir: /some/cni/bin/dir +criSocketPath: /some/cri.sock +databasePath: /some/file.db +disableKVM: true +disableLogging: true +downloadProtocol: http +enableRegexpImageTranslation: false +enableSriov: true +fdServerSocketPath: /some/fd/server.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /some/translation/dir +libvirtURI: qemu:///foobar +logLevel: 3 +rawDevices: sd* +skipImageTranslation: false diff --git a/pkg/config/TestConfigForNode__mapping_by_node_name__no_match_.out.yaml b/pkg/config/TestConfigForNode__mapping_by_node_name__no_match_.out.yaml new file mode 100755 index 000000000..75883e0b1 --- /dev/null +++ b/pkg/config/TestConfigForNode__mapping_by_node_name__no_match_.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: false +disableLogging: false +downloadProtocol: https +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: loop* +skipImageTranslation: false diff --git a/pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels.out.yaml b/pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels.out.yaml new file mode 100755 index 000000000..46d1942a7 --- /dev/null +++ b/pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: true +disableLogging: false +downloadProtocol: http +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: vd* +skipImageTranslation: false diff --git a/pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels_and_a_local_config.out.yaml b/pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels_and_a_local_config.out.yaml new file mode 100755 index 000000000..cada7d15e --- /dev/null +++ b/pkg/config/TestConfigForNode__mapping_by_node_name_and_multiple_labels_and_a_local_config.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: false +disableLogging: false +downloadProtocol: http +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: vd* +skipImageTranslation: false diff --git a/pkg/config/TestConfigForNode__no_mappings.out.yaml b/pkg/config/TestConfigForNode__no_mappings.out.yaml new file mode 100755 index 000000000..75883e0b1 --- /dev/null +++ b/pkg/config/TestConfigForNode__no_mappings.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: false +disableLogging: false +downloadProtocol: https +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: loop* +skipImageTranslation: false diff --git a/pkg/config/TestDefaultVirtletConfig.out.yaml b/pkg/config/TestDefaultVirtletConfig.out.yaml new file mode 100755 index 000000000..75883e0b1 --- /dev/null +++ b/pkg/config/TestDefaultVirtletConfig.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: false +disableLogging: false +downloadProtocol: https +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: loop* +skipImageTranslation: false diff --git a/pkg/config/TestLoadMappings.out.yaml b/pkg/config/TestLoadMappings.out.yaml new file mode 100755 index 000000000..d26298ca0 --- /dev/null +++ b/pkg/config/TestLoadMappings.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: true +disableLogging: false +downloadProtocol: https +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: sd* +skipImageTranslation: false diff --git a/pkg/config/TestMergeConfigs__all_cli_opts.out.yaml b/pkg/config/TestMergeConfigs__all_cli_opts.out.yaml new file mode 100755 index 000000000..e4aecf658 --- /dev/null +++ b/pkg/config/TestMergeConfigs__all_cli_opts.out.yaml @@ -0,0 +1,15 @@ +calicoSubnetSize: 22 +cniConfigDir: /some/cni/conf/dir +cniPluginDir: /some/cni/bin/dir +criSocketPath: /some/cri.sock +databasePath: /some/file.db +disableKVM: true +disableLogging: true +downloadProtocol: http +enableRegexpImageTranslation: false +enableSriov: true +fdServerSocketPath: /some/fd/server.sock +imageDir: /some/image/dir +imageTranslationConfigsDir: /some/translation/dir +libvirtURI: qemu:///foobar +rawDevices: sd* diff --git a/pkg/config/TestMergeConfigs__all_cli_opts__env.out.txt b/pkg/config/TestMergeConfigs__all_cli_opts__env.out.txt new file mode 100755 index 000000000..84910d12a --- /dev/null +++ b/pkg/config/TestMergeConfigs__all_cli_opts__env.out.txt @@ -0,0 +1,15 @@ +export VIRTLET_FD_SERVER_SOCKET_PATH=/some/fd/server.sock +export VIRTLET_DATABASE_PATH=/some/file.db +export VIRTLET_DOWNLOAD_PROTOCOL=http +export VIRTLET_IMAGE_DIR=/some/image/dir +export VIRTLET_IMAGE_TRANSLATIONS_DIR=/some/translation/dir +export VIRTLET_LIBVIRT_URI=qemu:///foobar +export VIRTLET_RAW_DEVICES=sd\* +export VIRTLET_CRI_SOCKET_PATH=/some/cri.sock +export VIRTLET_DISABLE_LOGGING=1 +export VIRTLET_DISABLE_KVM=1 +export VIRTLET_SRIOV_SUPPORT=1 +export VIRTLET_CNI_PLUGIN_DIR=/some/cni/bin/dir +export VIRTLET_CNI_CONFIG_DIR=/some/cni/conf/dir +export VIRTLET_CALICO_SUBNET=22 +export IMAGE_REGEXP_TRANSLATION='' diff --git a/pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config.out.yaml b/pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config.out.yaml new file mode 100755 index 000000000..4dd685257 --- /dev/null +++ b/pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 22 +cniConfigDir: /some/cni/conf/dir +cniPluginDir: /some/cni/bin/dir +criSocketPath: /some/cri.sock +databasePath: /some/file.db +disableKVM: true +disableLogging: true +downloadProtocol: http +enableRegexpImageTranslation: false +enableSriov: true +fdServerSocketPath: /some/fd/server.sock +imageDir: /some/image/dir +imageTranslationConfigsDir: /some/translation/dir +libvirtURI: qemu:///foobar +logLevel: 1 +rawDevices: sd* +skipImageTranslation: false diff --git a/pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config__env.out.txt b/pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config__env.out.txt new file mode 100755 index 000000000..26c658777 --- /dev/null +++ b/pkg/config/TestMergeConfigs__all_cli_opts_and_explicit_default_config__env.out.txt @@ -0,0 +1,16 @@ +export VIRTLET_FD_SERVER_SOCKET_PATH=/some/fd/server.sock +export VIRTLET_DATABASE_PATH=/some/file.db +export VIRTLET_DOWNLOAD_PROTOCOL=http +export VIRTLET_IMAGE_DIR=/some/image/dir +export VIRTLET_IMAGE_TRANSLATIONS_DIR=/some/translation/dir +export VIRTLET_LIBVIRT_URI=qemu:///foobar +export VIRTLET_RAW_DEVICES=sd\* +export VIRTLET_CRI_SOCKET_PATH=/some/cri.sock +export VIRTLET_DISABLE_LOGGING=1 +export VIRTLET_DISABLE_KVM=1 +export VIRTLET_SRIOV_SUPPORT=1 +export VIRTLET_CNI_PLUGIN_DIR=/some/cni/bin/dir +export VIRTLET_CNI_CONFIG_DIR=/some/cni/conf/dir +export VIRTLET_CALICO_SUBNET=22 +export IMAGE_REGEXP_TRANSLATION='' +export VIRTLET_LOGLEVEL=1 diff --git a/pkg/config/TestMergeConfigs__defaults.out.yaml b/pkg/config/TestMergeConfigs__defaults.out.yaml new file mode 100755 index 000000000..0967ef424 --- /dev/null +++ b/pkg/config/TestMergeConfigs__defaults.out.yaml @@ -0,0 +1 @@ +{} diff --git a/pkg/config/TestMergeConfigs__defaults__env.out.txt b/pkg/config/TestMergeConfigs__defaults__env.out.txt new file mode 100755 index 000000000..e69de29bb diff --git a/pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config_.out.yaml b/pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config_.out.yaml new file mode 100755 index 000000000..75883e0b1 --- /dev/null +++ b/pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config_.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 24 +cniConfigDir: /etc/cni/net.d +cniPluginDir: /opt/cni/bin +criSocketPath: /run/virtlet.sock +databasePath: /var/lib/virtlet/virtlet.db +disableKVM: false +disableLogging: false +downloadProtocol: https +enableRegexpImageTranslation: true +enableSriov: false +fdServerSocketPath: /var/lib/virtlet/tapfdserver.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /etc/virtlet/images +libvirtURI: qemu:///system +logLevel: 1 +rawDevices: loop* +skipImageTranslation: false diff --git a/pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config___env.out.txt b/pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config___env.out.txt new file mode 100755 index 000000000..c894c3ff5 --- /dev/null +++ b/pkg/config/TestMergeConfigs__defaults__explicitly_set_as_a_config___env.out.txt @@ -0,0 +1,16 @@ +export VIRTLET_FD_SERVER_SOCKET_PATH=/var/lib/virtlet/tapfdserver.sock +export VIRTLET_DATABASE_PATH=/var/lib/virtlet/virtlet.db +export VIRTLET_DOWNLOAD_PROTOCOL=https +export VIRTLET_IMAGE_DIR=/var/lib/virtlet/images +export VIRTLET_IMAGE_TRANSLATIONS_DIR=/etc/virtlet/images +export VIRTLET_LIBVIRT_URI=qemu:///system +export VIRTLET_RAW_DEVICES=loop\* +export VIRTLET_CRI_SOCKET_PATH=/run/virtlet.sock +export VIRTLET_DISABLE_LOGGING='' +export VIRTLET_DISABLE_KVM='' +export VIRTLET_SRIOV_SUPPORT='' +export VIRTLET_CNI_PLUGIN_DIR=/opt/cni/bin +export VIRTLET_CNI_CONFIG_DIR=/etc/cni/net.d +export VIRTLET_CALICO_SUBNET=24 +export IMAGE_REGEXP_TRANSLATION=1 +export VIRTLET_LOGLEVEL=1 diff --git a/pkg/config/TestMergeConfigs__opts_and_configs.out.yaml b/pkg/config/TestMergeConfigs__opts_and_configs.out.yaml new file mode 100755 index 000000000..7e684c3d2 --- /dev/null +++ b/pkg/config/TestMergeConfigs__opts_and_configs.out.yaml @@ -0,0 +1,5 @@ +calicoSubnetSize: 22 +disableKVM: true +enableSriov: true +libvirtURI: qemu:///foobar +rawDevices: sd* diff --git a/pkg/config/TestMergeConfigs__opts_and_configs__env.out.txt b/pkg/config/TestMergeConfigs__opts_and_configs__env.out.txt new file mode 100755 index 000000000..c60603f4c --- /dev/null +++ b/pkg/config/TestMergeConfigs__opts_and_configs__env.out.txt @@ -0,0 +1,5 @@ +export VIRTLET_LIBVIRT_URI=qemu:///foobar +export VIRTLET_RAW_DEVICES=sd\* +export VIRTLET_DISABLE_KVM=1 +export VIRTLET_SRIOV_SUPPORT=1 +export VIRTLET_CALICO_SUBNET=22 diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 000000000..f333ce38d --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,266 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "fmt" + "sort" + + virtletclient "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + flag "github.com/spf13/pflag" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + defaultFDServerSocketPath = "/var/lib/virtlet/tapfdserver.sock" + fdServerSocketPathEnv = "VIRTLET_FD_SERVER_SOCKET_PATH" + + defaultDatabasePath = "/var/lib/virtlet/virtlet.db" + databasePathEnv = "VIRTLET_DATABASE_PATH" + + defaultDownloadProtocol = "https" + imageDownloadProtocolEnv = "VIRTLET_DOWNLOAD_PROTOCOL" + + defaultImageDir = "/var/lib/virtlet/images" + imageDirEnv = "VIRTLET_IMAGE_DIR" + + defaultImageTranslationConfigsDir = "/etc/virtlet/images" + imageTranslationsConfigDirEnv = "VIRTLET_IMAGE_TRANSLATIONS_DIR" + + defaultLibvirtURI = "qemu:///system" + libvirtURIEnv = "VIRTLET_LIBVIRT_URI" + + defaultRawDevices = "loop*" + rawDevicesEnv = "VIRTLET_RAW_DEVICES" + + defaultCRISocketPath = "/run/virtlet.sock" + criSocketPathEnv = "VIRTLET_CRI_SOCKET_PATH" + + disableLoggingEnv = "VIRTLET_DISABLE_LOGGING" + disableKVMEnv = "VIRTLET_DISABLE_KVM" + enableSriovEnv = "VIRTLET_SRIOV_SUPPORT" + + defaultCNIPluginDir = "/opt/cni/bin" + cniPluginDirEnv = "VIRTLET_CNI_PLUGIN_DIR" + + defaultCNIConfigDir = "/etc/cni/net.d" + cniConfigDirEnv = "VIRTLET_CNI_CONFIG_DIR" + + defaultCalicoSubnet = 24 + calicoSubnetEnv = "VIRTLET_CALICO_SUBNET" + + enableRegexpImageTranslationEnv = "IMAGE_REGEXP_TRANSLATION" + logLevelEnv = "VIRTLET_LOGLEVEL" +) + +func configFieldSet(c *virtlet_v1.VirtletConfig) *fieldSet { + var fs fieldSet + fs.addStringField("fd-server-socket-path", "", "Path to fd server socket", fdServerSocketPathEnv, defaultFDServerSocketPath, &c.FDServerSocketPath) + fs.addStringField("database-path", "", "Path to the virtlet database", databasePathEnv, defaultDatabasePath, &c.DatabasePath) + fs.addStringField("image-download-protocol", "", "Image download protocol. Can be https or http", imageDownloadProtocolEnv, defaultDownloadProtocol, &c.DownloadProtocol) + fs.addStringField("image-dir", "", "Image directory", imageDirEnv, defaultImageDir, &c.ImageDir) + fs.addStringField("image-translation-configs-dir", "", "Image name translation configs directory", imageTranslationsConfigDirEnv, defaultImageTranslationConfigsDir, &c.ImageTranslationConfigsDir) + // SkipImageTranslation doesn't have corresponding flag or env var as it's only used by tests + fs.addBoolField("", "", "", "", false, &c.SkipImageTranslation) + fs.addStringField("libvirt-uri", "", "Libvirt connection URI", libvirtURIEnv, defaultLibvirtURI, &c.LibvirtURI) + fs.addStringField("raw-devices", "", "Comma separated list of raw device glob patterns which VMs can access (without '/dev/' prefix)", rawDevicesEnv, defaultRawDevices, &c.RawDevices) + fs.addStringField("listen", "", "The path to UNIX domain socket for CRI service to listen on", criSocketPathEnv, defaultCRISocketPath, &c.CRISocketPath) + fs.addBoolField("disable-logging", "", "Display logging and the streamer", disableLoggingEnv, false, &c.DisableLogging) + fs.addBoolField("disable-kvm", "", "Forcibly disable KVM support", disableKVMEnv, false, &c.DisableKVM) + fs.addBoolField("enable-sriov", "", "Enable SR-IOV support", enableSriovEnv, false, &c.EnableSriov) + fs.addStringField("cni-bin-dir", "", "Path to CNI plugin binaries", cniPluginDirEnv, defaultCNIPluginDir, &c.CNIPluginDir) + fs.addStringField("cni-conf-dir", "", "Path to the CNI configuration directory", cniConfigDirEnv, defaultCNIConfigDir, &c.CNIConfigDir) + fs.addIntField("calico-subnet-size", "", "Calico subnet size to use", calicoSubnetEnv, defaultCalicoSubnet, &c.CalicoSubnetSize) + fs.addBoolField("enable-regexp-image-translation", "", "Enable regexp image name translation", enableRegexpImageTranslationEnv, true, &c.EnableRegexpImageTranslation) + // this field duplicates glog's --v, so no option for it + fs.addIntField("", "", "", logLevelEnv, 1, &c.LogLevel) + return &fs +} + +// GetDefaultConfig returns a VirtletConfig with all values set to default +func GetDefaultConfig() *virtlet_v1.VirtletConfig { + var c virtlet_v1.VirtletConfig + configFieldSet(&c).applyDefaults() + return &c +} + +// Override replaces the values in the target config with those +// which are set in the other config. +func Override(target, other *virtlet_v1.VirtletConfig) { + configFieldSet(target).override(configFieldSet(other)) +} + +// DumpEnv returns a string with environment variable settings +// corresponding to the VirtletConfig. +func DumpEnv(c *virtlet_v1.VirtletConfig) string { + return configFieldSet(c).dumpEnv() +} + +func mappingMatches(cm virtlet_v1.VirtletConfigMapping, nodeName string, nodeLabels map[string]string) bool { + if cm.Config == nil { + return false + } + if cm.NodeName != "" && cm.NodeName != nodeName { + return false + } + if cm.Label != "" { + if _, found := nodeLabels[cm.Label]; !found { + return false + } + } + return true +} + +// MergeConfig merges several Virtlet configs together, with +// configs going later taking precedence. +func MergeConfigs(configs []*virtlet_v1.VirtletConfig) *virtlet_v1.VirtletConfig { + var cfg *virtlet_v1.VirtletConfig + for _, cur := range configs { + if cfg == nil { + cfg = cur + } else { + Override(cfg, cur) + } + } + return cfg +} + +// ConfigBinder is used to extract Virtlet config from a FlagSet. +type ConfigBinder struct { + flagSet *flag.FlagSet + config *virtlet_v1.VirtletConfig + fieldSet *fieldSet + lookupEnv envLookup +} + +// NewConfigBinder returns a new ConfigBinder. +func NewConfigBinder(flagSet *flag.FlagSet) *ConfigBinder { + config := &virtlet_v1.VirtletConfig{} + fs := configFieldSet(config) + fs.applyDefaults() + if flagSet != nil { + fs.addFlags(flagSet) + } + return &ConfigBinder{ + flagSet: flagSet, + config: config, + fieldSet: fs, + } +} + +// GetConfig returns the config that only includes the fields that +// were explicitly set in the flags. It should be called after parsing +// the flags. +func (cb *ConfigBinder) GetConfig() *virtlet_v1.VirtletConfig { + cb.fieldSet.clearFieldsNotInFlagSet(cb.flagSet) + cb.fieldSet.setFromEnv(cb.lookupEnv) + return cb.config +} + +// configForNode gets virtlet_v1.VirtletConfig for the specified node name and labels. +func configForNode(mappings []virtlet_v1.VirtletConfigMapping, localConfig *virtlet_v1.VirtletConfig, nodeName string, nodeLabels map[string]string) *virtlet_v1.VirtletConfig { + cfg := GetDefaultConfig() + var sortedMappings []virtlet_v1.VirtletConfigMapping + for _, m := range mappings { + if mappingMatches(m, nodeName, nodeLabels) { + sortedMappings = append(sortedMappings, m) + } + } + sort.Slice(sortedMappings, func(i, j int) bool { + a, b := sortedMappings[i], sortedMappings[j] + if a.NodeName == b.NodeName { + // This also covers the case where both names are empty. + return a.Label < b.Label + } else { + // This will place unnamed items earlier in the list. + // The order of node names among the items doesn't + // really matter as just one such item can match + // a node, but let's keep it stable. + return a.NodeName < b.NodeName + } + }) + + configs := []*virtlet_v1.VirtletConfig{cfg} + for _, m := range sortedMappings { + configs = append(configs, m.Config) + } + if localConfig != nil { + configs = append(configs, localConfig) + } + return MergeConfigs(configs) +} + +// NodeConfig is used to retrieve Virtlet configuration for the current +// node. +type NodeConfig struct { + clientCfg clientcmd.ClientConfig + kubeClient kubernetes.Interface + virtletClient virtletclient.Interface +} + +// NewNodeConfig creates a new NodeConfig +func NewNodeConfig(clientCfg clientcmd.ClientConfig) *NodeConfig { + return &NodeConfig{clientCfg: clientCfg} +} + +func (nc *NodeConfig) setup() error { + if nc.kubeClient != nil { + return nil + } + + config, err := nc.clientCfg.ClientConfig() + if err != nil { + return err + } + + kubeClient, err := kubernetes.NewForConfig(config) + if err != nil { + return fmt.Errorf("can't create kubernetes api client: %v", err) + } + + virtletClient, err := virtletclient.NewForConfig(config) + if err != nil { + return fmt.Errorf("can't create Virtlet api client: %v", err) + } + + nc.kubeClient = kubeClient + nc.virtletClient = virtletClient + return nil +} + +// LoadConfig loads the configuration for the specified node. +func (nc *NodeConfig) LoadConfig(localConfig *virtlet_v1.VirtletConfig, nodeName string) (*virtlet_v1.VirtletConfig, error) { + if err := nc.setup(); err != nil { + return nil, err + } + + node, err := nc.kubeClient.CoreV1().Nodes().Get(nodeName, meta_v1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("can't get node info for node %q: %v", nodeName, err) + } + + mappingList, err := nc.virtletClient.VirtletV1().VirtletConfigMappings("kube-system").List(meta_v1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list Virtlet config mappings: %v", err) + } + + return configForNode(mappingList.Items, localConfig, nodeName, node.Labels), nil +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go new file mode 100644 index 000000000..3cf20dd10 --- /dev/null +++ b/pkg/config/config_test.go @@ -0,0 +1,330 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or ≈git-agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "bufio" + "reflect" + "regexp" + "strings" + "testing" + + "github.com/Mirantis/virtlet/tests/gm" + "github.com/ghodss/yaml" + "github.com/kballard/go-shellquote" + flag "github.com/spf13/pflag" + v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fakekube "k8s.io/client-go/kubernetes/fake" + + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/fake" +) + +func TestDefaultVirtletConfig(t *testing.T) { + gm.Verify(t, gm.NewYamlVerifier(GetDefaultConfig())) +} + +func verifyEnv(t *testing.T, c *virtlet_v1.VirtletConfig) { + envText := DumpEnv(c) + gm.Verify(t, envText) + fakeEnv := map[string]string{} + scanner := bufio.NewScanner(strings.NewReader(envText)) + lineRx := regexp.MustCompile("^export ([^=]*)=(.*)") + for scanner.Scan() { + s := scanner.Text() + parts := lineRx.FindStringSubmatch(s) + if parts == nil { + t.Errorf("couldn't parse env string: %q", s) + } else { + subparts, err := shellquote.Split(parts[2]) + if err != nil { + t.Errorf("couldn't parse env string: %q: %v", s, err) + } + if len(subparts) != 1 { + t.Errorf("couldn't parse env string: %q", s) + } + fakeEnv[parts[1]] = subparts[0] + } + } + binder := NewConfigBinder(nil) + binder.lookupEnv = func(name string) (string, bool) { + r, found := fakeEnv[name] + return r, found + } + newConf := binder.GetConfig() + // this is a special case (test-only flag) + newConf.SkipImageTranslation = c.SkipImageTranslation + if !reflect.DeepEqual(newConf, c) { + origConfYaml, err := yaml.Marshal(c) + if err != nil { + t.Fatalf("Error marshalling yaml: %v", err) + } + newConfYaml, err := yaml.Marshal(newConf) + if err != nil { + t.Fatalf("Error marshalling yaml: %v", err) + } + t.Errorf("error reloading config from env. Was:\n%s\n--- became: ---\n%s", origConfYaml, newConfYaml) + } +} + +func TestMergeConfigs(t *testing.T) { + pstr := func(s string) *string { return &s } + pbool := func(b bool) *bool { return &b } + pint := func(i int) *int { return &i } + for _, tc := range []struct { + name, args string + configs []*virtlet_v1.VirtletConfig + }{ + { + name: "defaults", + args: "", + }, + { + name: "defaults (explicitly set as a config)", + args: "", + configs: []*virtlet_v1.VirtletConfig{GetDefaultConfig()}, + }, + { + name: "all cli opts", + args: "--fd-server-socket-path /some/fd/server.sock" + + " --database-path /some/file.db" + + " --image-download-protocol http" + + " --image-dir /some/image/dir" + + " --image-translation-configs-dir /some/translation/dir" + + " --libvirt-uri qemu:///foobar" + + " --raw-devices sd*" + + " --listen /some/cri.sock" + + " --disable-logging" + + " --disable-kvm" + + " --enable-sriov" + + " --cni-bin-dir /some/cni/bin/dir" + + " --cni-conf-dir /some/cni/conf/dir" + + " --calico-subnet-size 22" + + " --enable-regexp-image-translation=false", + }, + { + name: "all cli opts and explicit default config", + args: "--fd-server-socket-path /some/fd/server.sock" + + " --database-path /some/file.db" + + " --image-download-protocol http" + + " --image-dir /some/image/dir" + + " --image-translation-configs-dir /some/translation/dir" + + " --libvirt-uri qemu:///foobar" + + " --raw-devices sd*" + + " --listen /some/cri.sock" + + " --disable-logging" + + " --disable-kvm" + + " --enable-sriov" + + " --cni-bin-dir /some/cni/bin/dir" + + " --cni-conf-dir /some/cni/conf/dir" + + " --calico-subnet-size 22" + + " --enable-regexp-image-translation=false", + configs: []*virtlet_v1.VirtletConfig{GetDefaultConfig()}, + }, + { + name: "opts and configs", + args: "--raw-devices sd* --libvirt-uri qemu:///foobar", + configs: []*virtlet_v1.VirtletConfig{ + { + DisableKVM: pbool(true), + RawDevices: pstr("vd*"), + }, + { + EnableSriov: pbool(true), + CalicoSubnetSize: pint(22), + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + flags := flag.NewFlagSet("virtlet", flag.ContinueOnError) + configBinder := NewConfigBinder(flags) + if err := flags.Parse(strings.Split(tc.args, " ")); err != nil { + t.Fatalf("error parsing flags: %v", err) + } + cfg := MergeConfigs(append(tc.configs, configBinder.GetConfig())) + gm.Verify(t, gm.NewYamlVerifier(cfg)) + t.Run("env", func(t *testing.T) { + verifyEnv(t, cfg) + }) + }) + } +} + +const ( + fullConfig = ` +config: + fdServerSocketPath: /some/fd/server.sock + databasePath: /some/file.db + downloadProtocol: http + imageTranslationConfigsDir: /some/translation/dir + libvirtURI: qemu:///foobar + rawDevices: sd* + criSocketPath: /some/cri.sock + disableLogging: true + disableKVM: true + enableSriov: true + cniPluginDir: /some/cni/bin/dir + cniConfigDir: /some/cni/conf/dir + calicoSubnetSize: 22 + enableRegexpImageTranslation: false + logLevel: 3` + kubeNode1FullMapping = "nodeName: kube-node-1" + fullConfig + labelAFullMapping = "label: label-a" + fullConfig + anotherMapping1 = ` +nodeName: kube-node-1 +config: + enableSriov: false + disableKVM: true` + anotherMapping2 = ` +label: label-b +config: + rawDevices: vd* + downloadProtocol: http` + anotherMapping3 = ` +nodeName: kube-node-2 +config: + disableLogging: true` + anotherMapping4 = ` +label: label-a +config: + enableSriov: true + rawDevices: sd*` + sampleLocalConfig = ` +disableKVM: false +` +) + +func TestConfigForNode(t *testing.T) { + for _, tc := range []struct { + name string + mappings []string + nodeName string + nodeLabels map[string]string + localConfig string + }{ + { + name: "no mappings", + }, + { + name: "mapping by node name", + nodeName: "kube-node-1", + nodeLabels: map[string]string{"label-a": "1"}, + mappings: []string{kubeNode1FullMapping}, + }, + { + name: "mapping by node labels", + nodeName: "kube-node-1", + nodeLabels: map[string]string{"label-a": "1"}, + mappings: []string{labelAFullMapping}, + }, + { + name: "mapping by node name (no match)", + nodeName: "kube-node-2", + nodeLabels: map[string]string{"label-a": "1"}, + mappings: []string{kubeNode1FullMapping}, + }, + { + name: "mapping by node labels (no match)", + nodeName: "kube-node-1", + nodeLabels: map[string]string{"label-x": "1"}, + mappings: []string{labelAFullMapping}, + }, + { + name: "mapping by node name and multiple labels", + nodeName: "kube-node-1", + nodeLabels: map[string]string{"label-a": "1", "label-b": "1"}, + mappings: []string{anotherMapping1, anotherMapping2, anotherMapping3, anotherMapping4}, + }, + { + name: "mapping by node name and multiple labels and a local config", + nodeName: "kube-node-1", + nodeLabels: map[string]string{"label-a": "1", "label-b": "1"}, + mappings: []string{anotherMapping1, anotherMapping2, anotherMapping3, anotherMapping4}, + localConfig: sampleLocalConfig, + }, + } { + t.Run(tc.name, func(t *testing.T) { + var mappings []virtlet_v1.VirtletConfigMapping + for _, s := range tc.mappings { + var m virtlet_v1.VirtletConfigMapping + if err := yaml.Unmarshal([]byte(s), &m); err != nil { + t.Fatalf("Error parsing yaml: %v", err) + } + mappings = append(mappings, m) + copiedMapping := m.DeepCopyObject() + if !reflect.DeepEqual(copiedMapping, &m) { + t.Fatal("deep copy failed") + } + } + var localConfig *virtlet_v1.VirtletConfig + if tc.localConfig != "" { + if err := yaml.Unmarshal([]byte(tc.localConfig), &localConfig); err != nil { + t.Fatalf("Error parsing yaml: %v", err) + } + } + cfg := configForNode(mappings, localConfig, tc.nodeName, tc.nodeLabels) + gm.Verify(t, gm.NewYamlVerifier(cfg)) + }) + } +} + +func TestLoadMappings(t *testing.T) { + pstr := func(s string) *string { return &s } + pbool := func(b bool) *bool { return &b } + nc := NewNodeConfig(nil) + nc.kubeClient = fakekube.NewSimpleClientset( + &v1.Node{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "kube-node-1", + Labels: map[string]string{ + "label-a": "1", + "label-b": "1", + }, + }, + }) + nc.virtletClient = fake.NewSimpleClientset( + &virtlet_v1.VirtletConfigMapping{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "mapping-1", + Namespace: "kube-system", + }, + NodeName: "kube-node-1", + Config: &virtlet_v1.VirtletConfig{ + EnableSriov: pbool(true), + DisableKVM: pbool(true), + }, + }, + &virtlet_v1.VirtletConfigMapping{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "mapping-2", + Namespace: "kube-system", + }, + Label: "label-a", + Config: &virtlet_v1.VirtletConfig{ + RawDevices: pstr("sd*"), + }, + }) + cfg, err := nc.LoadConfig(&virtlet_v1.VirtletConfig{ + EnableSriov: pbool(false), + }, "kube-node-1") + if err != nil { + t.Fatalf("LoadConfig(): %v", err) + } + gm.Verify(t, gm.NewYamlVerifier(cfg)) +} diff --git a/pkg/config/fields.go b/pkg/config/fields.go new file mode 100644 index 000000000..d18a5080e --- /dev/null +++ b/pkg/config/fields.go @@ -0,0 +1,268 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or ≈git-agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "bytes" + "fmt" + "os" + "strconv" + + "github.com/golang/glog" + "github.com/kballard/go-shellquote" + flag "github.com/spf13/pflag" +) + +type configField interface { + flagName() string + envName() string + applyDefault() + clear() + present() bool + addFlag(f *flag.FlagSet) + override(from configField) + setFromEnvValue(value string) + envValue() string +} + +type fieldBase struct { + name string + shorthand string + usage string + env string +} + +func (f *fieldBase) flagName() string { return f.name } +func (f *fieldBase) envName() string { return f.env } + +type stringField struct { + fieldBase + defValue string + value **string +} + +var _ configField = &stringField{} + +func (sf *stringField) applyDefault() { + if *sf.value == nil { + *sf.value = &sf.defValue + } +} + +func (sf *stringField) clear() { *sf.value = nil } +func (sf *stringField) present() bool { return *sf.value != nil } + +func (sf *stringField) addFlag(f *flag.FlagSet) { + f.StringVarP(*sf.value, sf.name, sf.shorthand, sf.defValue, sf.usage) +} + +func (sf *stringField) override(from configField) { + fromValue := *from.(*stringField).value + if fromValue != nil { + v := *fromValue + *sf.value = &v + } +} + +func (sf *stringField) setFromEnvValue(value string) { + *sf.value = &value +} + +func (sf *stringField) envValue() string { + if *sf.value == nil { + return "" + } + return **sf.value +} + +type boolField struct { + fieldBase + defValue bool + value **bool +} + +var _ configField = &boolField{} + +func (bf *boolField) applyDefault() { + if *bf.value == nil { + *bf.value = &bf.defValue + } +} + +func (bf *boolField) clear() { *bf.value = nil } +func (bf *boolField) present() bool { return *bf.value != nil } + +func (bf *boolField) addFlag(f *flag.FlagSet) { + f.BoolVarP(*bf.value, bf.name, bf.shorthand, bf.defValue, bf.usage) +} + +func (bf *boolField) override(from configField) { + fromValue := *from.(*boolField).value + if fromValue != nil { + v := *fromValue + *bf.value = &v + } +} + +func (bf *boolField) setFromEnvValue(value string) { + v := value != "" + *bf.value = &v +} + +func (bf *boolField) envValue() string { + if *bf.value == nil || !**bf.value { + return "" + } + return "1" +} + +type intField struct { + fieldBase + defValue int + value **int +} + +var _ configField = &intField{} + +func (intf *intField) applyDefault() { + if *intf.value == nil { + *intf.value = &intf.defValue + } +} + +func (intf *intField) clear() { *intf.value = nil } +func (intf *intField) present() bool { return *intf.value != nil } + +func (intf *intField) addFlag(f *flag.FlagSet) { + f.IntVarP(*intf.value, intf.name, intf.shorthand, intf.defValue, intf.usage) +} + +func (intf *intField) override(from configField) { + fromValue := *from.(*intField).value + if fromValue != nil { + v := *fromValue + *intf.value = &v + } +} + +func (intf *intField) setFromEnvValue(value string) { + if v, err := strconv.Atoi(value); err != nil { + glog.Warningf("bad value for int field %s: %q", intf.name, value) + } else { + *intf.value = &v + } +} + +func (intf *intField) envValue() string { + if *intf.value == nil { + return "" + } + return strconv.Itoa(**intf.value) +} + +type envLookup func(name string) (string, bool) + +type fieldSet struct { + fields []configField +} + +func (fs *fieldSet) addStringField(name, shorthand, usage, env, defValue string, value **string) { + fs.addField(&stringField{ + fieldBase{name, shorthand, usage, env}, + defValue, + value, + }) +} + +func (fs *fieldSet) addBoolField(name, shorthand, usage, env string, defValue bool, value **bool) { + fs.addField(&boolField{ + fieldBase{name, shorthand, usage, env}, + defValue, + value, + }) +} + +func (fs *fieldSet) addIntField(name, shorthand, usage, env string, defValue int, value **int) { + fs.addField(&intField{ + fieldBase{name, shorthand, usage, env}, + defValue, + value, + }) +} + +func (fs *fieldSet) addField(cf configField) { + fs.fields = append(fs.fields, cf) +} + +func (fs *fieldSet) applyDefaults() { + for _, f := range fs.fields { + f.applyDefault() + } +} + +func (fs *fieldSet) addFlags(flagSet *flag.FlagSet) { + for _, f := range fs.fields { + if f.flagName() != "" { + f.addFlag(flagSet) + } + } +} + +func (fs *fieldSet) override(from *fieldSet) { + for n, f := range fs.fields { + f.override(from.fields[n]) + } +} + +func (fs *fieldSet) copyFrom(from *fieldSet) { + for n, f := range fs.fields { + f.clear() + f.override(from.fields[n]) + } +} + +func (fs *fieldSet) clearFieldsNotInFlagSet(flagSet *flag.FlagSet) { + for _, f := range fs.fields { + if flagSet == nil || f.flagName() == "" || !flagSet.Changed(f.flagName()) { + f.clear() + } + } +} + +func (fs *fieldSet) setFromEnv(lookupEnv envLookup) { + if lookupEnv == nil { + lookupEnv = os.LookupEnv + } + for _, f := range fs.fields { + if f.envName() == "" { + continue + } + if v, found := lookupEnv(f.envName()); found { + f.setFromEnvValue(v) + } + } +} + +func (fs *fieldSet) dumpEnv() string { + var buf bytes.Buffer + for _, f := range fs.fields { + if f.envName() != "" && f.present() { + fmt.Fprintf(&buf, "export %s=%s\n", f.envName(), shellquote.Join(f.envValue())) + } + } + return buf.String() +} diff --git a/pkg/imagetranslation/crd_source.go b/pkg/imagetranslation/crd_source.go index 9937eabf8..bd0e04d66 100644 --- a/pkg/imagetranslation/crd_source.go +++ b/pkg/imagetranslation/crd_source.go @@ -20,7 +20,7 @@ import ( "context" "fmt" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/utils" ) diff --git a/pkg/imagetranslation/fake_source.go b/pkg/imagetranslation/fake_source.go index 3a2bdfc21..d2d719dea 100644 --- a/pkg/imagetranslation/fake_source.go +++ b/pkg/imagetranslation/fake_source.go @@ -19,7 +19,7 @@ package imagetranslation import ( "context" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" ) type objectConfig struct { @@ -30,7 +30,7 @@ type objectConfig struct { var _ TranslationConfig = objectConfig{} // Name implements TranslationConfig Name -func (c objectConfig) Name() string { +func (c objectConfig) ConfigName() string { return c.name } diff --git a/pkg/imagetranslation/file_source.go b/pkg/imagetranslation/file_source.go index a97afd865..7afb4ae82 100644 --- a/pkg/imagetranslation/file_source.go +++ b/pkg/imagetranslation/file_source.go @@ -24,7 +24,7 @@ import ( "github.com/ghodss/yaml" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" ) type fileConfigSource struct { @@ -62,7 +62,7 @@ func (cs fileConfigSource) Description() string { } // Name implements TranslationConfig Name -func (c fileConfig) Name() string { +func (c fileConfig) ConfigName() string { return c.name } diff --git a/pkg/imagetranslation/interface.go b/pkg/imagetranslation/interface.go index ca9d9703c..6c6ae6a17 100644 --- a/pkg/imagetranslation/interface.go +++ b/pkg/imagetranslation/interface.go @@ -19,14 +19,14 @@ package imagetranslation import ( "context" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/image" ) // TranslationConfig represents a single config (prefix + rule list) in a config-set type TranslationConfig interface { - // Name returns the config name (any string identifier) - Name() string + // ConfigName returns the config name (any string identifier) + ConfigName() string // Payload returns ImageTranslation object associated with the config Payload() (v1.ImageTranslation, error) diff --git a/pkg/imagetranslation/translator.go b/pkg/imagetranslation/translator.go index fe381b6df..d9bdef84f 100644 --- a/pkg/imagetranslation/translator.go +++ b/pkg/imagetranslation/translator.go @@ -24,20 +24,18 @@ import ( "crypto/x509" "encoding/pem" "errors" - "os" "regexp" "strings" "time" "github.com/golang/glog" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/image" ) type imageNameTranslator struct { - AllowRegexp bool - + allowRegexp bool translations map[string]*v1.ImageTranslation } @@ -53,11 +51,11 @@ func (t *imageNameTranslator) LoadConfigs(ctx context.Context, sources ...Config for _, cfg := range configs { body, err := cfg.Payload() if err != nil { - glog.V(2).Infof("cannot load image translation config %s from %s: %v", cfg.Name(), source.Description(), err) + glog.V(2).Infof("cannot load image translation config %s from %s: %v", cfg.ConfigName(), source.Description(), err) continue } - translations[cfg.Name()] = &body + translations[cfg.ConfigName()] = &body } } t.translations = translations @@ -172,7 +170,7 @@ func (t *imageNameTranslator) Translate(name string) image.Endpoint { return convertEndpoint(r, translation) } } - if !t.AllowRegexp { + if !t.allowRegexp { continue } for _, r := range translation.Rules { @@ -196,23 +194,22 @@ func (t *imageNameTranslator) Translate(name string) image.Endpoint { } // NewImageNameTranslator creates an instance of ImageNameTranslator -func NewImageNameTranslator() ImageNameTranslator { - env := strings.ToUpper(os.Getenv("IMAGE_REGEXP_TRANSLATION")) +func NewImageNameTranslator(allowRegexp bool) ImageNameTranslator { return &imageNameTranslator{ - AllowRegexp: env != "", + allowRegexp: allowRegexp, } } // GetDefaultImageTranslator returns a default image translation that // uses CRDs and a config directory -func GetDefaultImageTranslator(imageTranslationConfigsDir string) image.Translator { +func GetDefaultImageTranslator(imageTranslationConfigsDir string, allowRegexp bool) image.Translator { var sources []ConfigSource sources = append(sources, NewCRDSource("kube-system")) if imageTranslationConfigsDir != "" { sources = append(sources, NewFileConfigSource(imageTranslationConfigsDir)) } return func(ctx context.Context, name string) image.Endpoint { - translator := NewImageNameTranslator() + translator := NewImageNameTranslator(allowRegexp) translator.LoadConfigs(ctx, sources...) return translator.Translate(name) } @@ -222,6 +219,6 @@ func GetDefaultImageTranslator(imageTranslationConfigsDir string) image.Translat // doesn't apply any translations func GetEmptyImageTranslator() image.Translator { return func(ctx context.Context, name string) image.Endpoint { - return NewImageNameTranslator().Translate(name) + return NewImageNameTranslator(false).Translate(name) } } diff --git a/pkg/imagetranslation/translator_test.go b/pkg/imagetranslation/translator_test.go index 396ef3e98..9ffa2c021 100644 --- a/pkg/imagetranslation/translator_test.go +++ b/pkg/imagetranslation/translator_test.go @@ -20,7 +20,7 @@ import ( "context" "testing" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" ) // TestTranslations tests how image names are translated with various translation rules @@ -57,9 +57,6 @@ func TestTranslations(t *testing.T) { }, } - translator := NewImageNameTranslator().(*imageNameTranslator) - translator.LoadConfigs(context.Background(), NewFakeConfigSource(configs)) - for _, tc := range []struct { name string allowRegexp bool @@ -128,7 +125,8 @@ func TestTranslations(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - translator.AllowRegexp = tc.allowRegexp + translator := NewImageNameTranslator(tc.allowRegexp).(*imageNameTranslator) + translator.LoadConfigs(context.Background(), NewFakeConfigSource(configs)) endpoint := translator.Translate(tc.imageName) if tc.expectedURL != endpoint.URL { t.Errorf("expected URL %q, but got %q", tc.expectedURL, endpoint.URL) diff --git a/pkg/imagetranslation/transport_test.go b/pkg/imagetranslation/transport_test.go index f86a30fb4..a98315d47 100644 --- a/pkg/imagetranslation/transport_test.go +++ b/pkg/imagetranslation/transport_test.go @@ -28,7 +28,7 @@ import ( "testing" "time" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/image" testutils "github.com/Mirantis/virtlet/pkg/utils/testing" ) @@ -39,7 +39,7 @@ func translate(config v1.ImageTranslation, name string, server *httptest.Server) } configs := map[string]v1.ImageTranslation{"config": config} - translator := NewImageNameTranslator() + translator := NewImageNameTranslator(true) translator.LoadConfigs(context.Background(), NewFakeConfigSource(configs)) return translator.Translate(name) } diff --git a/pkg/libvirttools/virtualization.go b/pkg/libvirttools/virtualization.go index b6e449e03..2bf265c88 100644 --- a/pkg/libvirttools/virtualization.go +++ b/pkg/libvirttools/virtualization.go @@ -18,9 +18,7 @@ package libvirttools import ( "fmt" - "os" "path/filepath" - "strings" "time" "github.com/golang/glog" @@ -76,6 +74,7 @@ type domainSettings struct { cpuQuota int64 rootDiskFilepath string netFdKey string + enableSriov bool } func (ds *domainSettings) createDomain(config *types.VMConfig) *libvirtxml.Domain { @@ -165,91 +164,88 @@ func (ds *domainSettings) createDomain(config *types.VMConfig) *libvirtxml.Domai }, } - if os.Getenv("VIRTLET_SRIOV_SUPPORT") != "" { + if ds.enableSriov { domain.QEMUCommandline.Envs = append(domain.QEMUCommandline.Envs, libvirtxml.DomainQEMUCommandlineEnv{Name: "VMWRAPPER_KEEP_PRIVS", Value: "1"}) } + return domain } -func canUseKvm() bool { - if os.Getenv("VIRTLET_DISABLE_KVM") != "" { - glog.V(0).Infof("VIRTLET_DISABLE_KVM env var not empty, using plain qemu") - return false +// VirtualizationConfig specifies configuration options for VirtualizationTool. +type VirtualizationConfig struct { + // True if KVM should be disabled + DisableKVM bool + // True if SR-IOV support needs to be enabled + EnableSriov bool + // List of raw devices that can be accessed by the VM. + RawDevices []string + // Kubelet's root dir + // FIXME: kubelet's --root-dir may be something other than /var/lib/kubelet + // Need to remove it from daemonset mounts (both dev and non-dev) + // Use 'nsenter -t 1 -m -- tar ...' or something to grab the path + // from root namespace + KubeletRootDir string + // The path of streamer socket used for + // logging. By default, the path is empty. When the path is empty, + // logging is disabled for the VMs. + StreamerSocketPath string + // The name of libvirt volume pool to use for the VMs. + VolumePoolName string +} + +func (c *VirtualizationConfig) applyDefaults() { + if c.KubeletRootDir == "" { + c.KubeletRootDir = defaultKubeletRootDir } - return true } // VirtualizationTool provides methods to operate on libvirt. type VirtualizationTool struct { - domainConn virt.DomainConnection - storageConn virt.StorageConnection - volumePoolName string - imageManager ImageManager - metadataStore metadata.Store - clock clockwork.Clock - forceKVM bool - kubeletRootDir string - rawDevices []string - volumeSource VMVolumeSource - streamerSocketPath string + domainConn virt.DomainConnection + storageConn virt.StorageConnection + imageManager ImageManager + metadataStore metadata.Store + clock clockwork.Clock + volumeSource VMVolumeSource + config VirtualizationConfig } var _ volumeOwner = &VirtualizationTool{} // NewVirtualizationTool verifies existence of volumes pool in libvirt store // and returns initialized VirtualizationTool. -func NewVirtualizationTool(domainConn virt.DomainConnection, storageConn virt.StorageConnection, imageManager ImageManager, - metadataStore metadata.Store, volumePoolName, rawDevices string, volumeSource VMVolumeSource) *VirtualizationTool { +func NewVirtualizationTool(domainConn virt.DomainConnection, + storageConn virt.StorageConnection, imageManager ImageManager, + metadataStore metadata.Store, volumeSource VMVolumeSource, + config VirtualizationConfig) *VirtualizationTool { + config.applyDefaults() return &VirtualizationTool{ - domainConn: domainConn, - storageConn: storageConn, - volumePoolName: volumePoolName, - imageManager: imageManager, - metadataStore: metadataStore, - clock: clockwork.NewRealClock(), - // FIXME: kubelet's --root-dir may be something other than /var/lib/kubelet - // Need to remove it from daemonset mounts (both dev and non-dev) - // Use 'nsenter -t 1 -m -- tar ...' or something to grab the path - // from root namespace - kubeletRootDir: defaultKubeletRootDir, - rawDevices: strings.Split(rawDevices, ","), - volumeSource: volumeSource, + domainConn: domainConn, + storageConn: storageConn, + imageManager: imageManager, + metadataStore: metadataStore, + clock: clockwork.NewRealClock(), + volumeSource: volumeSource, + config: config, } } -// SetForceKVM forces VirtualizationTool to use KVM (used in tests) -func (v *VirtualizationTool) SetForceKVM(forceKVM bool) { - v.forceKVM = forceKVM -} - // SetClock sets the clock to use (used in tests) func (v *VirtualizationTool) SetClock(clock clockwork.Clock) { v.clock = clock } -// SetKubeletRootDir sets kubelet root dir for VirtualizationTool -func (v *VirtualizationTool) SetKubeletRootDir(kubeletRootDir string) { - v.kubeletRootDir = kubeletRootDir -} - -// SetStreamerSocketPath sets the path of streamer socket used for -// logging. By default, the path is empty. When the path is empty, -// logging is disabled for the VMs. -func (v *VirtualizationTool) SetStreamerSocketPath(streamerSocketPath string) { - v.streamerSocketPath = streamerSocketPath -} - func (v *VirtualizationTool) addSerialDevicesToDomain(domain *libvirtxml.Domain) error { port := uint(0) timeout := uint(1) - if v.streamerSocketPath != "" { + if v.config.StreamerSocketPath != "" { domain.Devices.Serials = []libvirtxml.DomainSerial{ { Source: &libvirtxml.DomainChardevSource{ UNIX: &libvirtxml.DomainChardevSourceUNIX{ Mode: "connect", - Path: v.streamerSocketPath, + Path: v.config.StreamerSocketPath, Reconnect: &libvirtxml.DomainChardevSourceReconnect{ Enabled: "yes", Timeout: &timeout, @@ -289,24 +285,26 @@ func (v *VirtualizationTool) CreateContainer(config *types.VMConfig, netFdKey st domainUUID: domainUUID, // Note: using only first 13 characters because libvirt has an issue with handling // long path names for qemu monitor socket - domainName: "virtlet-" + domainUUID[:13] + "-" + config.Name, - netFdKey: netFdKey, - } - - settings.vcpuNum = config.ParsedAnnotations.VCPUCount - settings.memory = int(config.MemoryLimitInBytes) - settings.cpuShares = uint(config.CPUShares) - settings.cpuPeriod = uint64(config.CPUPeriod) - // Specified cpu bandwidth limits for domains actually are set equal per each vCPU by libvirt - // Thus, to limit overall VM's cpu threads consumption by set value in pod definition need to perform division - settings.cpuQuota = config.CPUQuota / int64(settings.vcpuNum) - settings.memoryUnit = "b" + domainName: "virtlet-" + domainUUID[:13] + "-" + config.Name, + netFdKey: netFdKey, + vcpuNum: config.ParsedAnnotations.VCPUCount, + memory: int(config.MemoryLimitInBytes), + cpuShares: uint(config.CPUShares), + cpuPeriod: uint64(config.CPUPeriod), + enableSriov: v.config.EnableSriov, + // CPU bandwidth limits for domains are actually set equal per + // each vCPU by libvirt. Thus, to limit overall VM's CPU + // threads consumption by the value from the pod definition + // we need to perform this division + cpuQuota: config.CPUQuota / int64(config.ParsedAnnotations.VCPUCount), + memoryUnit: "b", + useKvm: !v.config.DisableKVM, + } if settings.memory == 0 { settings.memory = defaultMemory settings.memoryUnit = defaultMemoryUnit } - settings.useKvm = v.forceKVM || canUseKvm() domainDef := settings.createDomain(config) diskList, err := newDiskList(config, v.volumeSource, v) @@ -796,7 +794,7 @@ func (v *VirtualizationTool) ContainerInfo(containerID string) (*types.Container // StoragePool implements volumeOwner StoragePool method func (v *VirtualizationTool) StoragePool() (virt.StoragePool, error) { - return ensureStoragePool(v.storageConn, v.volumePoolName) + return ensureStoragePool(v.storageConn, v.config.VolumePoolName) } // DomainConnection implements volumeOwner DomainConnection method @@ -806,10 +804,10 @@ func (v *VirtualizationTool) DomainConnection() virt.DomainConnection { return v func (v *VirtualizationTool) ImageManager() ImageManager { return v.imageManager } // RawDevices implements volumeOwner RawDevices method -func (v *VirtualizationTool) RawDevices() []string { return v.rawDevices } +func (v *VirtualizationTool) RawDevices() []string { return v.config.RawDevices } // KubeletRootDir implements volumeOwner KubeletRootDir method -func (v *VirtualizationTool) KubeletRootDir() string { return v.kubeletRootDir } +func (v *VirtualizationTool) KubeletRootDir() string { return v.config.KubeletRootDir } func filterContainer(containerInfo *types.ContainerInfo, filter types.ContainerFilter) bool { if filter.Id != "" && containerInfo.Id != filter.Id { diff --git a/pkg/libvirttools/virtualization_test.go b/pkg/libvirttools/virtualization_test.go index 9ea0fcec1..9efb4020c 100644 --- a/pkg/libvirttools/virtualization_test.go +++ b/pkg/libvirttools/virtualization_test.go @@ -84,13 +84,15 @@ func newContainerTester(t *testing.T, rec *testutils.TopLevelRecorder) *containe } imageManager := NewFakeImageManager(ct.rec) - ct.virtTool = NewVirtualizationTool(ct.domainConn, ct.storageConn, imageManager, ct.metadataStore, "volumes", "loop*", GetDefaultVolumeSource()) - ct.virtTool.SetClock(ct.clock) - // avoid unneeded diffs in the golden master data - ct.virtTool.SetForceKVM(true) ct.kubeletRootDir = filepath.Join(ct.tmpDir, "kubelet-root") - ct.virtTool.SetKubeletRootDir(ct.kubeletRootDir) - ct.virtTool.SetStreamerSocketPath("/var/lib/libvirt/streamer.sock") + virtConfig := VirtualizationConfig{ + VolumePoolName: "volumes", + RawDevices: []string{"loop*"}, + KubeletRootDir: ct.kubeletRootDir, + StreamerSocketPath: "/var/lib/libvirt/streamer.sock", + } + ct.virtTool = NewVirtualizationTool(ct.domainConn, ct.storageConn, imageManager, ct.metadataStore, GetDefaultVolumeSource(), virtConfig) + ct.virtTool.SetClock(ct.clock) return ct } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index f60d4eaef..c2f2afb35 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -23,7 +23,7 @@ import ( "github.com/golang/glog" - "github.com/Mirantis/virtlet/pkg/api/types/v1" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/image" "github.com/Mirantis/virtlet/pkg/imagetranslation" "github.com/Mirantis/virtlet/pkg/libvirttools" @@ -33,62 +33,16 @@ import ( ) const ( - defaultDownloadProtocol = "https" tapManagerConnectInterval = 200 * time.Millisecond tapManagerAttemptCount = 50 - defaultLibvirtURI = "qemu:///system" streamerSocketPath = "/var/lib/libvirt/streamer.sock" - defaultCRISocketPath = "/run/virtlet.sock" + volumePoolName = "volumes" ) -// VirtletConfig denotes a configuration for VirtletManager. -type VirtletConfig struct { - // FdServerSocketPath specifies the path to fdServer socket. - FDServerSocketPath string - // FDManager specifies an FDManager to use to set up - // the pod networking. If it's set, FDServerSocketPath is ignored. - FDManager tapmanager.FDManager - // DatabasePath specifies the path to Virtlet database. - DatabasePath string - // DownloadProtocol specifies the download protocol to use. - // It defaults to "https" - DownloadProtocol string - // ImageDir specifies the image store directory. - ImageDir string - // ImageTranslationConfigsDir specifies the directory with - // image translation configuration files. Empty string means - // such directory is not used. - ImageTranslationConfigsDir string - // SkipImageTranslation disables image translations - SkipImageTranslation bool - // LibvirtURI specifies the libvirt connnection URI - LibvirtURI string - // RawDevices specifies a comma-separated list of raw device - // glob patterns which VMs can access - RawDevices string - // CRISocketPath specifies the socket path for the gRPC endpoint. - CRISocketPath string - // DisableLogging disables the streaming server - DisableLogging bool -} - -// ApplyDefaults applies default settings to VirtletConfig -func (c *VirtletConfig) applyDefaults() { - if c.LibvirtURI == "" { - c.LibvirtURI = defaultLibvirtURI - } - if c.DownloadProtocol == "" { - c.DownloadProtocol = defaultDownloadProtocol - } - if c.CRISocketPath == "" { - c.CRISocketPath = defaultCRISocketPath - } -} - // VirtletManager wraps the Virtlet's Runtime and Image CRI services, // as well as a gRPC server that provides access to them. type VirtletManager struct { - config *VirtletConfig + config *v1.VirtletConfig metadataStore metadata.Store fdManager tapmanager.FDManager virtTool *libvirttools.VirtualizationTool @@ -99,20 +53,17 @@ type VirtletManager struct { } // NewVirtletManager creates a new VirtletManager. -func NewVirtletManager(config *VirtletConfig) *VirtletManager { - return &VirtletManager{config: config} +func NewVirtletManager(config *v1.VirtletConfig, fdManager tapmanager.FDManager) *VirtletManager { + return &VirtletManager{config: config, fdManager: fdManager} } // Run sets up the environment for the runtime and image services and // starts the gRPC listener. It doesn't return until the server is // stopped or an error occurs. func (v *VirtletManager) Run() error { - v.config.applyDefaults() var err error - if v.config.FDManager != nil { - v.fdManager = v.config.FDManager - } else { - client := tapmanager.NewFDClient(v.config.FDServerSocketPath) + if v.fdManager == nil { + client := tapmanager.NewFDClient(*v.config.FDServerSocketPath) for i := 0; i < tapManagerAttemptCount; i++ { time.Sleep(tapManagerConnectInterval) if err = client.Connect(); err == nil { @@ -125,35 +76,41 @@ func (v *VirtletManager) Run() error { v.fdManager = client } - v.metadataStore, err = metadata.NewStore(v.config.DatabasePath) + v.metadataStore, err = metadata.NewStore(*v.config.DatabasePath) if err != nil { return fmt.Errorf("failed to create metadata store: %v", err) } - downloader := image.NewDownloader(v.config.DownloadProtocol) - v.imageStore = image.NewFileStore(v.config.ImageDir, downloader, nil) + downloader := image.NewDownloader(*v.config.DownloadProtocol) + v.imageStore = image.NewFileStore(*v.config.ImageDir, downloader, nil) v.imageStore.SetRefGetter(v.metadataStore.ImagesInUse) var translator image.Translator - if !v.config.SkipImageTranslation { + if !*v.config.SkipImageTranslation { if err = v1.RegisterCustomResourceTypes(); err != nil { return fmt.Errorf("failed to register image translation CRD: %v", err) } - translator = imagetranslation.GetDefaultImageTranslator(v.config.ImageTranslationConfigsDir) + translator = imagetranslation.GetDefaultImageTranslator(*v.config.ImageTranslationConfigsDir, *v.config.EnableRegexpImageTranslation) } else { translator = imagetranslation.GetEmptyImageTranslator() } - conn, err := libvirttools.NewConnection(v.config.LibvirtURI) + conn, err := libvirttools.NewConnection(*v.config.LibvirtURI) if err != nil { return fmt.Errorf("error establishing libvirt connection: %v", err) } - volSrc := libvirttools.GetDefaultVolumeSource() - v.virtTool = libvirttools.NewVirtualizationTool(conn, conn, v.imageStore, v.metadataStore, "volumes", v.config.RawDevices, volSrc) + virtConfig := libvirttools.VirtualizationConfig{ + DisableKVM: *v.config.DisableKVM, + EnableSriov: *v.config.EnableSriov, + VolumePoolName: volumePoolName, + } + if *v.config.RawDevices != "" { + virtConfig.RawDevices = strings.Split(*v.config.RawDevices, ",") + } var streamServer StreamServer - if !v.config.DisableLogging { + if !*v.config.DisableLogging { s, err := stream.NewServer(streamerSocketPath, v.metadataStore) if err != nil { return fmt.Errorf("couldn't create stream server: %v", err) @@ -165,9 +122,12 @@ func (v *VirtletManager) Run() error { } streamServer = s - v.virtTool.SetStreamerSocketPath(streamerSocketPath) + virtConfig.StreamerSocketPath = streamerSocketPath } + volSrc := libvirttools.GetDefaultVolumeSource() + v.virtTool = libvirttools.NewVirtualizationTool(conn, conn, v.imageStore, v.metadataStore, volSrc, virtConfig) + runtimeService := NewVirtletRuntimeService(v.virtTool, v.metadataStore, v.fdManager, streamServer, v.imageStore, nil) imageService := NewVirtletImageService(v.imageStore, translator) @@ -180,7 +140,7 @@ func (v *VirtletManager) Run() error { } glog.V(1).Infof("Starting server on socket %s", v.config.CRISocketPath) - if err = v.server.Serve(v.config.CRISocketPath); err != nil { + if err = v.server.Serve(*v.config.CRISocketPath); err != nil { return fmt.Errorf("serving failed: %v", err) } diff --git a/pkg/manager/runtime_test.go b/pkg/manager/runtime_test.go index 52e93c402..5449abbec 100644 --- a/pkg/manager/runtime_test.go +++ b/pkg/manager/runtime_test.go @@ -229,13 +229,15 @@ func makeVirtletCRITester(t *testing.T) *virtletCRITester { domainConn := fakevirt.NewFakeDomainConnection(rec.Child("domain conn")) storageConn := fakevirt.NewFakeStorageConnection(rec.Child("storage")) clock := clockwork.NewFakeClockAt(time.Unix(0, podTimestap)) - virtTool := libvirttools.NewVirtualizationTool(domainConn, storageConn, imageStore, metadataStore, "volumes", "loop*", libvirttools.GetDefaultVolumeSource()) - virtTool.SetClock(clock) - // avoid unneeded diffs in the golden master data - virtTool.SetForceKVM(true) kubeletRootDir := filepath.Join(tmpDir, "kubelet-root") - virtTool.SetKubeletRootDir(kubeletRootDir) - virtTool.SetStreamerSocketPath(streamerSocketPath) + virtConfig := libvirttools.VirtualizationConfig{ + VolumePoolName: "volumes", + RawDevices: []string{"loop*"}, + KubeletRootDir: kubeletRootDir, + StreamerSocketPath: streamerSocketPath, + } + virtTool := libvirttools.NewVirtualizationTool(domainConn, storageConn, imageStore, metadataStore, libvirttools.GetDefaultVolumeSource(), virtConfig) + virtTool.SetClock(clock) streamServer := newFakeStreamServer(rec.Child("streamServer")) criHandler := &criHandler{ VirtletRuntimeService: NewVirtletRuntimeService(virtTool, metadataStore, fdManager, streamServer, imageStore, clock), @@ -655,7 +657,4 @@ func TestCRIAttachPortForward(t *testing.T) { tst.verify() } -// TODO: use interceptor for logging in the manager -// (apply it only if glog level is high enough) -// TODO: make sure non-default namespace settings cause pod startup to fail. -// TODO: don't use criapi, convert test objects from metadata instead +// TODO: make sure non-default Linux namespace settings cause pod startup to fail. diff --git a/pkg/nettools/nettools.go b/pkg/nettools/nettools.go index 4917b29ff..38883aeb8 100644 --- a/pkg/nettools/nettools.go +++ b/pkg/nettools/nettools.go @@ -44,7 +44,6 @@ import ( "os/exec" "path/filepath" "sort" - "strconv" "strings" "github.com/containernetworking/cni/pkg/ns" @@ -67,9 +66,6 @@ const ( sizeOfIfReq = 40 ifnamsiz = 16 - - calicoDefaultSubnet = 24 - calicoSubnetVar = "VIRTLET_CALICO_SUBNET" ) // Had to duplicate ifReq here as it's not exported @@ -727,7 +723,7 @@ func getVfVlanID(pciAddress string) (int, error) { // In case of SR-IOV VFs this function only sets up a device to be passed to VM. // The function should be called from within container namespace. // Returns container network struct and an error, if any. -func SetupContainerSideNetwork(info *cnicurrent.Result, nsPath string, allLinks []netlink.Link) (*network.ContainerSideNetwork, error) { +func SetupContainerSideNetwork(info *cnicurrent.Result, nsPath string, allLinks []netlink.Link, enableSriov bool) (*network.ContainerSideNetwork, error) { contLinks, err := GetContainerLinks(info) if err != nil { return nil, err @@ -749,7 +745,7 @@ func SetupContainerSideNetwork(info *cnicurrent.Result, nsPath string, allLinks } if isSriovVf(link) { - if os.Getenv("VIRTLET_SRIOV_SUPPORT") == "" { + if !enableSriov { return nil, fmt.Errorf("SR-IOV device configured in container network namespace while Virtlet is configured with disabled SR-IOV support") } @@ -1197,7 +1193,7 @@ func getDummyGateway(dummyNetwork *cnicurrent.Result) (net.IP, error) { // responses for VMs. // This function must be called from within the container network // namespace. -func FixCalicoNetworking(netConfig *cnicurrent.Result, getDummyNetwork func() (*cnicurrent.Result, string, error)) error { +func FixCalicoNetworking(netConfig *cnicurrent.Result, calicoSubnetSize int, getDummyNetwork func() (*cnicurrent.Result, string, error)) error { for n, ipConfig := range netConfig.IPs { link, err := getLinkForIPConfig(netConfig, n) if err != nil { @@ -1211,7 +1207,7 @@ func FixCalicoNetworking(netConfig *cnicurrent.Result, getDummyNetwork func() (* if !haveCalico { continue } - ipConfig.Address.Mask = netmaskForCalico() + ipConfig.Address.Mask = net.CIDRMask(calicoSubnetSize, 32) if haveCalicoGateway { dummyNetwork, nsPath, err := getDummyNetwork() if err != nil { @@ -1262,17 +1258,3 @@ func FixCalicoNetworking(netConfig *cnicurrent.Result, getDummyNetwork func() (* } return nil } - -func netmaskForCalico() net.IPMask { - n := calicoDefaultSubnet - subnetStr := os.Getenv(calicoSubnetVar) - if subnetStr != "" { - var err error - n, err = strconv.Atoi(subnetStr) - if err != nil || n <= 0 || n > 30 { - glog.Warningf("bad calico subnet %q, using /%d", subnetStr, calicoDefaultSubnet) - n = calicoDefaultSubnet - } - } - return net.CIDRMask(n, 32) -} diff --git a/pkg/nettools/nettools_test.go b/pkg/nettools/nettools_test.go index 6493c509a..20c7080a0 100644 --- a/pkg/nettools/nettools_test.go +++ b/pkg/nettools/nettools_test.go @@ -398,7 +398,7 @@ func verifyContainerSideNetwork(t *testing.T, origContVeth netlink.Link, contNsP origHwAddr := origContVeth.Attrs().HardwareAddr expectedInfo := expectedExtractedLinkInfo(contNsPath) - csn, err := SetupContainerSideNetwork(expectedInfo, contNsPath, allLinks) + csn, err := SetupContainerSideNetwork(expectedInfo, contNsPath, allLinks, false) if err != nil { log.Panicf("failed to set up container side network: %v", err) } @@ -535,7 +535,7 @@ func TestTeardownContainerSideNetwork(t *testing.T) { log.Panicf("error listing links: %v", err) } - csn, err := SetupContainerSideNetwork(expectedExtractedLinkInfo(contNS.Path()), contNS.Path(), allLinks) + csn, err := SetupContainerSideNetwork(expectedExtractedLinkInfo(contNS.Path()), contNS.Path(), allLinks, false) if err != nil { log.Panicf("failed to set up container side network: %v", err) } @@ -763,7 +763,7 @@ func TestFixCalicoNetworking(t *testing.T) { log.Panicf("failed to grab interface info: %v", err) } // reuse 2nd copy of the CNI result as the dummy network config - if err := FixCalicoNetworking(info, func() (*cnicurrent.Result, string, error) { + if err := FixCalicoNetworking(info, 24, func() (*cnicurrent.Result, string, error) { return dummyInfo, dummyNS.Path(), nil }); err != nil { log.Panicf("FixCalicoNetworking(): %v", err) diff --git a/pkg/tapmanager/tapfdsource.go b/pkg/tapmanager/tapfdsource.go index 4a40664d2..f35853bbf 100644 --- a/pkg/tapmanager/tapfdsource.go +++ b/pkg/tapmanager/tapfdsource.go @@ -92,16 +92,19 @@ type TapFDSource struct { dummyNetwork *cnicurrent.Result dummyNetworkNsPath string fdMap map[string]*podNetwork + enableSriov bool + calicoSubnetSize int } var _ FDSource = &TapFDSource{} // NewTapFDSource returns a TapFDSource for the specified CNI plugin & // config dir -func NewTapFDSource(cniClient cni.Client) (*TapFDSource, error) { +func NewTapFDSource(cniClient cni.Client, enableSriov bool, calicoSubnetSize int) (*TapFDSource, error) { s := &TapFDSource{ - cniClient: cniClient, - fdMap: make(map[string]*podNetwork), + cniClient: cniClient, + fdMap: make(map[string]*podNetwork), + calicoSubnetSize: calicoSubnetSize, } return s, nil @@ -172,14 +175,14 @@ func (s *TapFDSource) GetFDs(key string, data []byte) ([]int, []byte, error) { gotError = true return nil, fmt.Errorf("error fixing cni configuration: %v", err) } - if err := nettools.FixCalicoNetworking(netConfig, s.getDummyNetwork); err != nil { + if err := nettools.FixCalicoNetworking(netConfig, s.calicoSubnetSize, s.getDummyNetwork); err != nil { // don't fail in this case because there may be even no Calico glog.Warningf("Calico detection/fix didn't work: %v", err) } glog.V(3).Infof("CNI Result after fix:\n%s", spew.Sdump(netConfig)) var err error - if csn, err = nettools.SetupContainerSideNetwork(netConfig, netNSPath, allLinks); err != nil { + if csn, err = nettools.SetupContainerSideNetwork(netConfig, netNSPath, allLinks, s.enableSriov); err != nil { return nil, err } diff --git a/pkg/tools/TestGenCommand__compat.out.yaml b/pkg/tools/TestGenCommand__compat.out.yaml index 1006f6f43..58f1bfe0c 100755 --- a/pkg/tools/TestGenCommand__compat.out.yaml +++ b/pkg/tools/TestGenCommand__compat.out.yaml @@ -25,19 +25,6 @@ spec: containers: - command: - /libvirt.sh - env: - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true image: mirantis/virtlet imagePullPolicy: IfNotPresent name: libvirt @@ -73,58 +60,7 @@ spec: name: libvirt-log - mountPath: /dev name: dev - - env: - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true - - name: VIRTLET_DOWNLOAD_PROTOCOL - valueFrom: - configMapKeyRef: - key: download_protocol - name: virtlet-config - optional: true - - name: VIRTLET_LOGLEVEL - valueFrom: - configMapKeyRef: - key: loglevel - name: virtlet-config - optional: true - - name: VIRTLET_CALICO_SUBNET - valueFrom: - configMapKeyRef: - key: calico-subnet - name: virtlet-config - optional: true - - name: IMAGE_REGEXP_TRANSLATION - valueFrom: - configMapKeyRef: - key: image_regexp_translation - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_LOGGING - valueFrom: - configMapKeyRef: - key: disable_logging - name: virtlet-config - optional: true - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_RAW_DEVICES - valueFrom: - configMapKeyRef: - key: raw_devices - name: virtlet-config - optional: true - - name: IMAGE_TRANSLATIONS_DIR - value: /etc/virtlet/images - image: mirantis/virtlet + - image: mirantis/virtlet imagePullPolicy: IfNotPresent name: virtlet readinessProbe: @@ -185,12 +121,61 @@ spec: - command: - /prepare-node.sh env: + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName - name: VIRTLET_DISABLE_KVM valueFrom: configMapKeyRef: key: disable_kvm name: virtlet-config optional: true + - name: VIRTLET_SRIOV_SUPPORT + valueFrom: + configMapKeyRef: + key: sriov_support + name: virtlet-config + optional: true + - name: VIRTLET_DOWNLOAD_PROTOCOL + valueFrom: + configMapKeyRef: + key: download_protocol + name: virtlet-config + optional: true + - name: VIRTLET_LOGLEVEL + valueFrom: + configMapKeyRef: + key: loglevel + name: virtlet-config + optional: true + - name: VIRTLET_CALICO_SUBNET + valueFrom: + configMapKeyRef: + key: calico-subnet + name: virtlet-config + optional: true + - name: IMAGE_REGEXP_TRANSLATION + valueFrom: + configMapKeyRef: + key: image_regexp_translation + name: virtlet-config + optional: true + - name: VIRTLET_RAW_DEVICES + valueFrom: + configMapKeyRef: + key: raw_devices + name: virtlet-config + optional: true + - name: VIRTLET_DISABLE_LOGGING + valueFrom: + configMapKeyRef: + key: disable_logging + name: virtlet-config + optional: true + - name: VIRTLET_IMAGE_TRANSLATIONS_DIR + value: /etc/virtlet/images image: mirantis/virtlet imagePullPolicy: IfNotPresent name: prepare-node @@ -210,6 +195,8 @@ spec: name: var-lib - mountPath: /dev name: dev + - mountPath: /var/lib/virtlet + name: virtlet serviceAccountName: virtlet volumes: - hostPath: diff --git a/pkg/tools/TestGenCommand__compat_dev.out.yaml b/pkg/tools/TestGenCommand__compat_dev.out.yaml index 21899b529..eec905a88 100755 --- a/pkg/tools/TestGenCommand__compat_dev.out.yaml +++ b/pkg/tools/TestGenCommand__compat_dev.out.yaml @@ -25,19 +25,6 @@ spec: containers: - command: - /libvirt.sh - env: - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true image: mirantis/virtlet imagePullPolicy: IfNotPresent name: libvirt @@ -75,58 +62,7 @@ spec: name: dev - mountPath: /dind name: dind - - env: - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true - - name: VIRTLET_DOWNLOAD_PROTOCOL - valueFrom: - configMapKeyRef: - key: download_protocol - name: virtlet-config - optional: true - - name: VIRTLET_LOGLEVEL - valueFrom: - configMapKeyRef: - key: loglevel - name: virtlet-config - optional: true - - name: VIRTLET_CALICO_SUBNET - valueFrom: - configMapKeyRef: - key: calico-subnet - name: virtlet-config - optional: true - - name: IMAGE_REGEXP_TRANSLATION - valueFrom: - configMapKeyRef: - key: image_regexp_translation - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_LOGGING - valueFrom: - configMapKeyRef: - key: disable_logging - name: virtlet-config - optional: true - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_RAW_DEVICES - valueFrom: - configMapKeyRef: - key: raw_devices - name: virtlet-config - optional: true - - name: IMAGE_TRANSLATIONS_DIR - value: /etc/virtlet/images - image: mirantis/virtlet + - image: mirantis/virtlet imagePullPolicy: IfNotPresent name: virtlet readinessProbe: @@ -191,12 +127,61 @@ spec: - command: - /prepare-node.sh env: + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName - name: VIRTLET_DISABLE_KVM valueFrom: configMapKeyRef: key: disable_kvm name: virtlet-config optional: true + - name: VIRTLET_SRIOV_SUPPORT + valueFrom: + configMapKeyRef: + key: sriov_support + name: virtlet-config + optional: true + - name: VIRTLET_DOWNLOAD_PROTOCOL + valueFrom: + configMapKeyRef: + key: download_protocol + name: virtlet-config + optional: true + - name: VIRTLET_LOGLEVEL + valueFrom: + configMapKeyRef: + key: loglevel + name: virtlet-config + optional: true + - name: VIRTLET_CALICO_SUBNET + valueFrom: + configMapKeyRef: + key: calico-subnet + name: virtlet-config + optional: true + - name: IMAGE_REGEXP_TRANSLATION + valueFrom: + configMapKeyRef: + key: image_regexp_translation + name: virtlet-config + optional: true + - name: VIRTLET_RAW_DEVICES + valueFrom: + configMapKeyRef: + key: raw_devices + name: virtlet-config + optional: true + - name: VIRTLET_DISABLE_LOGGING + valueFrom: + configMapKeyRef: + key: disable_logging + name: virtlet-config + optional: true + - name: VIRTLET_IMAGE_TRANSLATIONS_DIR + value: /etc/virtlet/images image: mirantis/virtlet imagePullPolicy: IfNotPresent name: prepare-node @@ -216,6 +201,8 @@ spec: name: var-lib - mountPath: /dev name: dev + - mountPath: /var/lib/virtlet + name: virtlet - mountPath: /dind name: dind serviceAccountName: virtlet diff --git a/pkg/tools/TestGenCommand__dev.out.yaml b/pkg/tools/TestGenCommand__dev.out.yaml index 1f5f5449f..1ce77ea3e 100755 --- a/pkg/tools/TestGenCommand__dev.out.yaml +++ b/pkg/tools/TestGenCommand__dev.out.yaml @@ -25,19 +25,6 @@ spec: containers: - command: - /libvirt.sh - env: - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true image: mirantis/virtlet imagePullPolicy: IfNotPresent name: libvirt @@ -76,58 +63,7 @@ spec: name: dev - mountPath: /dind name: dind - - env: - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true - - name: VIRTLET_DOWNLOAD_PROTOCOL - valueFrom: - configMapKeyRef: - key: download_protocol - name: virtlet-config - optional: true - - name: VIRTLET_LOGLEVEL - valueFrom: - configMapKeyRef: - key: loglevel - name: virtlet-config - optional: true - - name: VIRTLET_CALICO_SUBNET - valueFrom: - configMapKeyRef: - key: calico-subnet - name: virtlet-config - optional: true - - name: IMAGE_REGEXP_TRANSLATION - valueFrom: - configMapKeyRef: - key: image_regexp_translation - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_LOGGING - valueFrom: - configMapKeyRef: - key: disable_logging - name: virtlet-config - optional: true - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_RAW_DEVICES - valueFrom: - configMapKeyRef: - key: raw_devices - name: virtlet-config - optional: true - - name: IMAGE_TRANSLATIONS_DIR - value: /etc/virtlet/images - image: mirantis/virtlet + - image: mirantis/virtlet imagePullPolicy: IfNotPresent name: virtlet readinessProbe: @@ -194,12 +130,61 @@ spec: - command: - /prepare-node.sh env: + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName - name: VIRTLET_DISABLE_KVM valueFrom: configMapKeyRef: key: disable_kvm name: virtlet-config optional: true + - name: VIRTLET_SRIOV_SUPPORT + valueFrom: + configMapKeyRef: + key: sriov_support + name: virtlet-config + optional: true + - name: VIRTLET_DOWNLOAD_PROTOCOL + valueFrom: + configMapKeyRef: + key: download_protocol + name: virtlet-config + optional: true + - name: VIRTLET_LOGLEVEL + valueFrom: + configMapKeyRef: + key: loglevel + name: virtlet-config + optional: true + - name: VIRTLET_CALICO_SUBNET + valueFrom: + configMapKeyRef: + key: calico-subnet + name: virtlet-config + optional: true + - name: IMAGE_REGEXP_TRANSLATION + valueFrom: + configMapKeyRef: + key: image_regexp_translation + name: virtlet-config + optional: true + - name: VIRTLET_RAW_DEVICES + valueFrom: + configMapKeyRef: + key: raw_devices + name: virtlet-config + optional: true + - name: VIRTLET_DISABLE_LOGGING + valueFrom: + configMapKeyRef: + key: disable_logging + name: virtlet-config + optional: true + - name: VIRTLET_IMAGE_TRANSLATIONS_DIR + value: /etc/virtlet/images image: mirantis/virtlet imagePullPolicy: IfNotPresent name: prepare-node @@ -220,6 +205,8 @@ spec: name: var-lib - mountPath: /dev name: dev + - mountPath: /var/lib/virtlet + name: virtlet - mountPath: /dind name: dind serviceAccountName: virtlet diff --git a/pkg/tools/TestGenCommand__plain.out.yaml b/pkg/tools/TestGenCommand__plain.out.yaml index 2fc8d8944..b384c1f39 100755 --- a/pkg/tools/TestGenCommand__plain.out.yaml +++ b/pkg/tools/TestGenCommand__plain.out.yaml @@ -54,15 +54,66 @@ spec: mountPath: /host-var-lib - name: dev mountPath: /dev + - mountPath: /var/lib/virtlet + name: virtlet securityContext: privileged: true env: + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName - name: VIRTLET_DISABLE_KVM valueFrom: configMapKeyRef: name: virtlet-config key: disable_kvm optional: true + - name: VIRTLET_SRIOV_SUPPORT + valueFrom: + configMapKeyRef: + name: virtlet-config + key: sriov_support + optional: true + - name: VIRTLET_DOWNLOAD_PROTOCOL + valueFrom: + configMapKeyRef: + name: virtlet-config + key: download_protocol + optional: true + - name: VIRTLET_LOGLEVEL + valueFrom: + configMapKeyRef: + name: virtlet-config + key: loglevel + optional: true + - name: VIRTLET_CALICO_SUBNET + valueFrom: + configMapKeyRef: + name: virtlet-config + key: calico-subnet + optional: true + - name: IMAGE_REGEXP_TRANSLATION + valueFrom: + configMapKeyRef: + name: virtlet-config + key: image_regexp_translation + optional: true + - name: VIRTLET_RAW_DEVICES + valueFrom: + configMapKeyRef: + name: virtlet-config + key: raw_devices + optional: true + - name: VIRTLET_DISABLE_LOGGING + valueFrom: + configMapKeyRef: + name: virtlet-config + key: disable_logging + optional: true + - name: VIRTLET_IMAGE_TRANSLATIONS_DIR + value: /etc/virtlet/images containers: - name: libvirt @@ -100,19 +151,6 @@ spec: mountPath: /dev securityContext: privileged: true - env: - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - name: virtlet-config - key: sriov_support - optional: true - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - name: virtlet-config - key: disable_kvm - optional: true readinessProbe: exec: command: @@ -153,57 +191,6 @@ spec: mountPath: /var/log/pods securityContext: privileged: true - env: - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - name: virtlet-config - key: disable_kvm - optional: true - - name: VIRTLET_DOWNLOAD_PROTOCOL - valueFrom: - configMapKeyRef: - name: virtlet-config - key: download_protocol - optional: true - - name: VIRTLET_LOGLEVEL - valueFrom: - configMapKeyRef: - name: virtlet-config - key: loglevel - optional: true - - name: VIRTLET_CALICO_SUBNET - valueFrom: - configMapKeyRef: - name: virtlet-config - key: calico-subnet - optional: true - - name: IMAGE_REGEXP_TRANSLATION - valueFrom: - configMapKeyRef: - name: virtlet-config - key: image_regexp_translation - optional: true - - name: VIRTLET_DISABLE_LOGGING - valueFrom: - configMapKeyRef: - name: virtlet-config - key: disable_logging - optional: true - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - name: virtlet-config - key: sriov_support - optional: true - - name: VIRTLET_RAW_DEVICES - valueFrom: - configMapKeyRef: - name: virtlet-config - key: raw_devices - optional: true - - name: IMAGE_TRANSLATIONS_DIR - value: /etc/virtlet/images readinessProbe: exec: command: diff --git a/pkg/tools/TestGenCommand__tag.out.yaml b/pkg/tools/TestGenCommand__tag.out.yaml index c4d61247b..cc04647a2 100755 --- a/pkg/tools/TestGenCommand__tag.out.yaml +++ b/pkg/tools/TestGenCommand__tag.out.yaml @@ -25,19 +25,6 @@ spec: containers: - command: - /libvirt.sh - env: - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true image: mirantis/virtlet:0.9.42 imagePullPolicy: IfNotPresent name: libvirt @@ -74,58 +61,7 @@ spec: name: libvirt-log - mountPath: /dev name: dev - - env: - - name: VIRTLET_DISABLE_KVM - valueFrom: - configMapKeyRef: - key: disable_kvm - name: virtlet-config - optional: true - - name: VIRTLET_DOWNLOAD_PROTOCOL - valueFrom: - configMapKeyRef: - key: download_protocol - name: virtlet-config - optional: true - - name: VIRTLET_LOGLEVEL - valueFrom: - configMapKeyRef: - key: loglevel - name: virtlet-config - optional: true - - name: VIRTLET_CALICO_SUBNET - valueFrom: - configMapKeyRef: - key: calico-subnet - name: virtlet-config - optional: true - - name: IMAGE_REGEXP_TRANSLATION - valueFrom: - configMapKeyRef: - key: image_regexp_translation - name: virtlet-config - optional: true - - name: VIRTLET_DISABLE_LOGGING - valueFrom: - configMapKeyRef: - key: disable_logging - name: virtlet-config - optional: true - - name: VIRTLET_SRIOV_SUPPORT - valueFrom: - configMapKeyRef: - key: sriov_support - name: virtlet-config - optional: true - - name: VIRTLET_RAW_DEVICES - valueFrom: - configMapKeyRef: - key: raw_devices - name: virtlet-config - optional: true - - name: IMAGE_TRANSLATIONS_DIR - value: /etc/virtlet/images - image: mirantis/virtlet:0.9.42 + - image: mirantis/virtlet:0.9.42 imagePullPolicy: IfNotPresent name: virtlet readinessProbe: @@ -188,12 +124,61 @@ spec: - command: - /prepare-node.sh env: + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName - name: VIRTLET_DISABLE_KVM valueFrom: configMapKeyRef: key: disable_kvm name: virtlet-config optional: true + - name: VIRTLET_SRIOV_SUPPORT + valueFrom: + configMapKeyRef: + key: sriov_support + name: virtlet-config + optional: true + - name: VIRTLET_DOWNLOAD_PROTOCOL + valueFrom: + configMapKeyRef: + key: download_protocol + name: virtlet-config + optional: true + - name: VIRTLET_LOGLEVEL + valueFrom: + configMapKeyRef: + key: loglevel + name: virtlet-config + optional: true + - name: VIRTLET_CALICO_SUBNET + valueFrom: + configMapKeyRef: + key: calico-subnet + name: virtlet-config + optional: true + - name: IMAGE_REGEXP_TRANSLATION + valueFrom: + configMapKeyRef: + key: image_regexp_translation + name: virtlet-config + optional: true + - name: VIRTLET_RAW_DEVICES + valueFrom: + configMapKeyRef: + key: raw_devices + name: virtlet-config + optional: true + - name: VIRTLET_DISABLE_LOGGING + valueFrom: + configMapKeyRef: + key: disable_logging + name: virtlet-config + optional: true + - name: VIRTLET_IMAGE_TRANSLATIONS_DIR + value: /etc/virtlet/images image: mirantis/virtlet:0.9.42 imagePullPolicy: IfNotPresent name: prepare-node @@ -214,6 +199,8 @@ spec: name: var-lib - mountPath: /dev name: dev + - mountPath: /var/lib/virtlet + name: virtlet serviceAccountName: virtlet volumes: - hostPath: diff --git a/pkg/tools/bindata.go b/pkg/tools/bindata.go index 3b1841e25..e3377599e 100644 --- a/pkg/tools/bindata.go +++ b/pkg/tools/bindata.go @@ -66,7 +66,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _deployDataVirtletDsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x5a\x5b\x73\xdb\xb8\x15\x7e\xf7\xaf\x38\xb3\x9e\x69\x92\x07\x5a\x76\xa6\xdb\x64\x35\xed\x83\x63\x6b\x5d\xcd\x3a\x96\x46\x72\x9c\x7d\xd3\x80\xe0\x91\x84\x15\x08\xb0\x07\x20\x6d\xf5\xd7\x77\x00\x5e\xc4\x8b\x24\x2b\xf1\x65\x37\x53\x3f\xc9\x00\xce\x87\x73\xbf\x90\x0c\x82\xe0\x88\x25\xe2\x0e\xc9\x08\xad\xfa\x80\x0f\x16\x95\xfb\x69\x7a\xd9\x59\x88\x96\x9d\x1d\xad\x84\x8a\xfa\x70\xc9\x30\xd6\x6a\x8a\xf6\x28\x46\xcb\x22\x66\x59\xff\x08\x40\xb1\x18\xfb\x90\x09\xb2\x12\x6d\xf1\xbf\x49\x18\xc7\x3e\xac\xd2\x10\x03\xb3\x36\x16\xe3\x23\x93\x20\x77\xc7\x2d\xc6\x89\x64\x16\xdd\x6f\x80\x3a\x90\xfb\x6b\x83\xb9\x3f\xc9\x42\x94\xa6\x3c\x01\x40\xa9\xb2\xa2\x7d\xac\x84\x77\x7f\x4b\x6d\xec\x0d\xda\x7b\x4d\xab\x3e\x58\x4a\xb1\x58\x8f\x94\x19\x6b\x29\xf8\xba\x0f\x17\x32\x35\x16\xe9\x57\x41\xc6\x7e\x15\x76\xf9\xef\x9c\xa4\x38\x78\xec\x21\xc6\xc3\x4b\x10\xc6\x03\x80\xd5\xf0\xf6\xec\x1d\xa0\x62\xa1\x44\xb8\xfb\x6c\xdc\x8a\x49\x29\x13\x19\x96\x7c\x00\xd7\xca\x32\xa1\x90\x80\xd0\x58\x46\x1b\xb8\xb7\x56\x43\x88\xc0\x97\xc8\x57\x18\xbd\x03\xa6\x22\x78\xfb\xfe\x9d\x03\x29\x20\xed\x12\x21\x35\x08\x7a\x0e\xca\xa0\xb2\x48\x20\x14\x08\x25\x6a\xb0\x35\xf1\xc6\xc3\xcb\x86\x68\xc7\x10\x6a\x6d\x8d\x25\x96\x40\x42\x9a\x63\x94\x12\x82\x42\x8c\x3c\xa7\x9c\x90\x59\x04\xe6\xb0\xe6\x62\x11\xb3\xc4\xa1\xd7\xcc\xb3\xb1\x5a\x01\x68\x90\x32\xc1\xf1\x9c\x73\x9d\x2a\x7b\xd3\x30\x4b\x75\xa7\x56\x72\xed\xcc\x01\x77\x85\x06\x12\x1d\x19\xd0\xca\x4b\xa3\x74\x84\x06\xee\x85\x5d\x3a\x8f\x22\x36\xc9\xcd\xf6\xaf\x52\x5b\xde\xac\x05\x14\x9b\xcf\x9d\xa8\xeb\x8d\x91\x1d\xf5\x79\x67\x15\x80\xf0\x3f\xa9\x20\x8c\x2e\x53\x12\x6a\x31\xe5\x4b\x8c\x52\x29\xd4\x62\xb8\x50\xba\x5a\x1e\x3c\x20\x4f\xad\x73\xe6\x1a\x65\x8e\x39\x45\x89\xdc\x6a\xba\x45\x8a\x4d\x73\x3b\x80\x98\x59\xbe\x1c\x3c\x24\x84\xc6\xfb\x7f\x73\xdf\x9d\x58\xe1\xba\xdf\x10\xa7\x75\x02\x40\x27\x48\xcc\x6a\xea\xc3\x50\x75\x36\x33\x26\x53\xec\xc0\x3a\xe0\x96\x6e\x9d\xdc\x17\xa5\xdd\x2b\x82\x63\xb8\x5d\x62\xcb\x29\x80\xeb\x44\xa0\x29\x01\xde\x18\x98\x4b\x7c\xc8\xb4\x4c\x63\x84\x88\x44\x56\xf9\xcd\xb1\xf3\x04\x67\x99\x08\xe7\x2c\x95\xd6\xdb\xdf\x5b\x4d\xa6\x0b\xa1\x20\x12\xe4\x1d\x13\x95\x49\x09\x0d\xd8\x25\xdb\x78\xb0\xa7\x13\xe4\x75\xe7\xae\x73\xae\x85\x11\x84\x6b\x90\x22\x74\x77\xc3\xdf\xaa\x38\xc0\x07\x61\x6c\xe9\x06\xce\x5b\x8f\x4a\x29\xf3\xf0\x4e\x08\x13\x46\x18\x38\x7b\x54\xaa\x10\x31\x5b\x60\x1f\x62\x41\x4c\x59\x61\x7a\xcd\x1c\x50\xec\x8f\x53\x29\xcb\x10\x1e\xce\x6f\xb4\x1d\x13\xba\x68\xa9\x4e\x71\x1d\xc7\x4c\x45\x1b\x0d\x07\xd0\xab\x5f\x77\x62\x96\xd5\x56\xae\xa3\xcf\xce\xbf\x4d\x9d\x20\x67\x72\xf5\xd1\x04\x1b\x4d\x06\xb9\x8e\x4c\x10\x09\xaa\x59\x2f\x76\xc4\x63\x66\x97\x7d\xe8\x15\xda\x0c\x9a\x04\x1d\x5c\x4a\x55\x07\x80\x74\xc2\x16\xcc\x3b\x2c\x7c\x12\xb9\x9a\x85\x56\x4c\xee\xb8\xaa\x8e\x51\xe2\x46\x9a\xaf\x90\x8c\xe6\xab\x1d\x44\x19\x23\x47\xd8\xcb\x0f\x9e\x34\x4e\x96\x20\x52\x2f\x76\x50\x3b\x33\xd6\x77\x8f\x61\xae\x29\x77\x15\xa1\x16\xde\x57\xf2\x2b\xa4\x08\x7b\x85\x4b\xf4\xbc\xcd\x4c\xee\x0f\x3e\x2f\x34\x2c\x5e\x5e\x9a\x31\x0a\xa4\x08\xf7\x5c\x1c\xb4\x8f\x54\x42\x63\xb6\x83\xac\xbe\x63\x90\xa7\x24\xec\xda\x05\x14\x3e\xd8\x7a\xf8\x25\x24\x32\x21\x71\x81\x51\x23\x9d\x02\xa0\xca\xba\x3e\x71\x37\x9c\xdc\x5e\x0f\x6e\x67\x97\xc3\xe9\xf9\xa7\xeb\xc1\xec\xb7\xbb\xcf\x35\x2c\x1f\xdc\xbf\x92\x8e\x9b\xf1\x9d\xa7\xdc\xcf\x2c\xf9\x0d\xd7\x13\x9c\xb7\x83\xbf\x51\xf1\x82\xfc\x70\xeb\x88\x4f\x3a\x91\x30\xae\x50\xcc\x56\x59\xdc\xda\xd6\x49\xee\x2c\x85\x04\x47\xd5\xb5\xad\xec\x51\x19\x39\xb7\xce\xc1\x91\x77\x0c\x43\x05\x9c\x19\x84\x7b\x97\x7c\xfe\x40\x6e\x41\x6a\xce\x64\x15\xf0\x1e\xc1\xed\xde\x33\x65\x5d\x96\x71\x95\x4c\x58\x50\xda\x82\x9e\xcf\x05\x17\x4c\xca\x35\xb0\x8c\x09\xe9\xab\x9d\x56\xf8\x0c\x81\x5d\x08\x72\x48\x4c\xd7\x5d\xc3\xac\x4d\x6f\x6e\x7a\x7c\x41\x3a\x4d\x8e\xda\x96\x68\x2d\x37\x49\x9d\x73\xc7\x3a\x4a\x25\x9a\x0e\x61\x77\x9d\x90\x45\x23\x25\xd7\x2d\xd7\x6a\x42\xba\xba\xdd\xc1\x6a\x2d\x1e\x04\xd4\x4c\x2c\x4f\x49\x36\x41\x27\x6f\x38\xb9\xdb\x6e\xb1\xbd\x59\xdb\x45\xdd\x76\x3a\xd8\xe1\x8c\x5d\x6a\x97\xb3\x1e\xa1\x0e\x5c\x32\x43\x6b\x6a\x2e\xeb\x4a\x8f\xd4\x0b\x5f\xd4\x44\x55\xae\x96\x48\x08\x21\x72\xe6\x5b\x2d\xbb\x44\xba\x17\x06\xab\x12\x76\x2f\xa4\x74\xed\x53\x94\x72\x04\x24\xd2\x54\x87\x94\x62\xe5\xfa\x34\x51\x73\xac\x63\xf8\x52\xb4\x6f\xda\x55\xb5\xa0\xe8\xb3\xf8\x92\x51\x84\x19\xcc\x85\x44\x78\x93\xeb\x40\x2f\x7a\x59\x6c\x7a\x6c\x1e\x7d\xf8\x39\x0c\xc3\xe0\x23\xfe\xf2\x21\x38\x3b\xc3\x0f\xc1\x2f\x3f\xff\xe3\x2c\x38\x7d\xff\xf7\xf7\xa7\x8c\x9f\x9e\x9e\x9e\xbe\xef\x71\x41\xa4\x4d\x90\xc5\xb3\xd3\x13\xa9\x17\x6f\xfa\x70\xe3\xba\x4d\xbe\xcc\x11\x35\x55\xa5\x78\xdd\xcd\xa6\xb1\x09\x76\xa7\xf1\x1a\x2b\xdd\xe4\x5f\x28\xf3\x71\xea\xae\xd1\xfe\xd4\x74\x3c\x9d\x0c\x47\x77\xb3\xe9\x97\xf1\x78\x34\xb9\x7d\xb5\x84\x6c\x48\xe8\x6c\x66\xd2\x24\xd1\x0d\xcf\x84\x6e\x4a\xde\xc5\xf8\x5f\xba\x8e\x94\xcb\x2e\xf9\x08\x85\xc6\x8c\x49\x87\x58\xbf\x16\x1f\x36\x33\x57\xc9\x63\x2b\x4b\xe7\x52\xf7\x42\xa1\x7a\xb5\x2c\x9d\xaf\x06\xbc\xb5\x60\x34\x67\x16\x02\xf8\x72\x33\xfc\xbd\xdf\x8e\xfd\x5e\x3d\xd6\x03\xd2\xf0\x4f\xe7\x54\x3d\x95\x4a\xd9\xaa\x6f\x5b\x3b\xc7\xbf\x7a\x7d\x3b\xa4\x70\x3d\x5f\x86\x3f\xce\xeb\x8e\x6f\xf7\xeb\x45\x0d\x18\x61\x35\x62\xb9\xe6\xde\xa4\x09\x52\x2c\xd4\x0f\x58\x0f\x7f\xc4\xba\xd5\x44\x49\x8d\xe7\xc1\x85\x99\x9f\x2e\x48\xa1\x45\x53\x0d\x1a\xc5\x84\xd1\xcb\x5d\xa7\xe7\x8e\x75\x2e\x3a\x60\x8a\xd9\x2e\x77\x71\x49\xcf\x4d\xf4\x5b\x51\xdd\xc6\xd6\x69\xe8\x90\xfe\xe2\xfb\x4b\x55\xfd\x04\x5a\x5e\x5a\xb7\x18\x35\x3a\x9c\xfa\xe5\xc0\xfd\x0e\x2c\x31\x65\xa4\x67\xac\x5b\xfb\xbc\x34\x8f\xf3\xd2\xd0\xc6\xff\xd7\x58\xb1\x93\xe9\xd1\xd7\x9b\xeb\xd1\xf9\xe5\x6c\x3c\x19\xdd\x8e\x2e\x46\xd7\xaf\xc7\xba\xbe\x57\x52\xb3\x68\x96\x90\xb6\x9a\x6b\xf9\x7d\x02\x5c\x8f\xae\xae\x07\x77\x83\xd7\xe3\x5b\xea\x85\xc4\x0c\xbf\x93\xdd\x8b\xf3\xeb\xe1\xc5\x68\x36\xfd\xf2\xe9\x66\xf0\x7a\xcd\x0e\x67\x52\x70\x1d\x98\x34\x54\xf8\x8d\xcd\xce\xf0\xf3\xf9\xd5\x60\x36\x19\x5c\x0d\x7e\x1f\xcf\x6e\x27\xe7\x37\xd3\xeb\xf3\xdb\xe1\xe8\xe6\xd5\x78\xf7\x39\x60\x46\xb8\xc0\x87\x64\x56\xcb\x02\x4f\xeb\xd9\xae\x47\x57\x57\xc3\x9b\xab\x57\x0f\x54\xa9\x17\x0b\xa1\xda\x47\x0e\x64\xfe\x87\xed\x94\x27\xe7\x5f\x67\x97\x83\xbb\xe1\xc5\x60\xfa\x6a\x6c\x13\xbb\x9f\x45\x98\x09\xde\xa8\x2b\x07\x30\x9d\x7b\x7c\xcd\xd5\xa7\xb3\xcb\xe1\xa4\xcd\xf7\xfe\x02\xf6\x67\x75\xdd\xae\x6b\x29\x58\xf2\x8f\x08\xf7\xb4\xd9\xb5\xba\xfc\x72\x0f\x6f\xb3\xd8\x7c\xeb\xf3\x9d\xd7\x6e\xfc\x9e\x3a\x77\x1f\x36\x35\x07\x3b\xdb\xea\xfd\x0d\x79\xae\xb1\xda\x2b\x04\x87\x5a\x7b\x24\x32\xd7\xe4\x9f\xd1\x3b\x77\x87\xdc\xdd\x81\x71\x8e\xc6\x54\xf6\xf6\x2f\x9c\x1c\x7e\xbd\xc3\xe9\x72\xd8\x96\x66\x2f\xe1\xf6\x87\x70\x5b\x1e\xc1\xed\x45\xd9\x36\x7f\x6c\x53\xd3\x5e\x90\xc6\x70\xd1\x99\x37\xf6\x92\xd6\xa7\xaf\xf6\x3c\x76\x0c\xb7\xa3\xcb\x91\x6b\x53\xd4\x1b\x0b\x4b\x46\x11\xd7\x11\x16\xcf\xe9\x21\xef\xfc\xfd\x9c\xe9\x72\x89\x7f\x32\xb5\x21\x5c\x0a\x93\x3f\x8c\x2a\x66\x31\xb8\x98\x0c\x21\x21\xfd\xb0\x06\xa1\x8c\x65\x32\xaf\x60\x6e\x14\xad\x5f\x28\x54\x6e\x4a\xef\x11\x9b\x57\x7a\x27\x87\x88\xb2\xef\xf5\xc0\x8e\x37\x0c\x8f\xe2\x6d\x8b\xc2\x6d\x31\x78\x10\x50\x3b\xf0\xb6\x85\xe3\xe3\x40\xb5\x08\x6d\xbf\xf2\xd8\x4b\xfc\x84\x59\xec\xc0\x49\xec\x20\x25\x6c\x1d\xcb\x76\x0e\x65\x87\x40\xb6\x0d\xd3\x78\xd3\x72\x88\x3e\xab\x0a\x56\xcf\x6d\xdb\x72\xe2\x41\x60\x7b\xad\xfc\x2d\x60\xdb\xc6\xef\x7d\xc3\xf7\x41\xdc\x6d\x51\x7b\x6b\x72\x3c\x88\x2f\x85\x56\xb5\x71\xfc\x5a\xc3\x76\x55\x1b\xd3\xdf\x55\xc2\x82\x7c\xbc\xdd\x3a\xd9\xee\x9f\x7f\xdb\xdf\x7c\x50\xc8\xf8\x09\x4b\xed\x52\x93\xf8\xaf\x3f\x73\xb2\xfa\x68\x4e\x84\x6e\x7d\x02\x52\x7c\x37\x31\xd1\x12\x3f\x09\x15\xb9\x46\x74\xf7\xb7\x20\xa4\x25\x16\xfd\x17\x4b\xc4\x95\x4b\xea\x7b\x6e\x3a\x02\xe8\xdc\xd1\x81\x34\x69\xf8\x07\x72\x57\xfb\x83\xe2\xf4\xb4\xf1\xa1\xc2\xe1\xdf\xa3\x38\x0d\x74\xef\xfb\x36\x9d\x7c\xc7\x67\x30\xe4\xaa\x92\x3b\x1f\x54\x3a\xa9\xbd\xa0\xfb\xe9\x27\xff\x93\xd0\xe8\x94\x38\xd6\x76\xaa\x0f\x37\x72\x0b\x67\x48\x61\x7d\xd7\xbf\x77\x78\x0e\xab\x6e\x91\xa9\xba\x3a\x70\x4d\x29\x52\x29\x43\x4b\x82\x82\xfb\x06\xef\x2d\xbe\x2b\xae\x03\x58\x78\x25\x05\x20\x85\xc9\x7f\xdc\x33\xcb\x97\x2f\x24\x41\x19\x2e\xa9\x41\x72\x3b\x4f\x16\x24\x00\x83\x9c\xf2\xe4\xd1\x12\xea\x45\x23\xab\x2c\x37\x4a\x47\x18\x84\xc5\xb1\x67\x0c\xb3\x8e\xa9\xeb\xf1\xf6\x2d\xe0\x57\x45\x07\x97\xc3\xe6\xbe\xdf\xf7\x5f\x04\xbd\x70\xea\x89\x37\x46\x7e\x01\xfd\xec\x72\xa4\x1f\x24\x2d\x05\x9c\xa2\xc7\x32\x10\x4b\xc4\xe6\x03\xc0\x02\x79\x77\x56\x4a\x8d\xd5\x71\xb9\x11\xa1\xff\x5e\xab\x2a\x43\xdb\x93\xd4\xae\x8b\xcb\xa9\x73\xf5\xd1\xec\xbc\xaf\x38\xe3\xab\x5a\xcc\x92\x44\xa8\xc5\xd6\xab\x8a\xac\x92\xff\xf3\xe2\x51\xd9\xd0\xee\xf3\x3b\x9b\x83\x7d\x5e\x07\xab\x6b\x22\x2b\x45\x6d\x01\x7e\x47\x6d\xfb\x5f\x00\x00\x00\xff\xff\x4a\x63\x3f\x61\x49\x2a\x00\x00") +var _deployDataVirtletDsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x5a\x5d\x73\xe2\x3a\xd2\xbe\xcf\xaf\xe8\x3a\xa9\x7a\x67\xe6\xc2\x71\x32\xf5\x9e\x9d\x39\xd4\xee\x05\x13\x38\x59\x6a\x12\xa0\x20\x93\x39\x77\x94\x2c\x37\x46\x8b\x2c\x79\x25\xd9\x09\xfb\xeb\xb7\x24\x1b\xe3\x2f\x08\xf9\xac\x1d\xae\xc0\x52\x3f\xea\x2f\x75\x3f\x12\xf6\x3c\xef\x84\x24\xec\x0e\x95\x66\x52\xf4\x00\x1f\x0c\x0a\xfb\x55\xfb\xd9\x45\x80\x86\x5c\x9c\xac\x99\x08\x7b\x30\x20\x18\x4b\x31\x47\x73\x12\xa3\x21\x21\x31\xa4\x77\x02\x20\x48\x8c\x3d\xc8\x98\x32\x1c\x4d\xf1\x5b\x27\x84\x62\x0f\xd6\x69\x80\x9e\xde\x68\x83\xf1\x89\x4e\x90\xda\xe9\x06\xe3\x84\x13\x83\xf6\x3b\x40\x15\xc8\x7e\x9a\x60\xf6\xc3\x49\x80\x5c\x6f\x67\x00\xa8\x54\x18\xd6\x9c\xb6\x85\xb7\x9f\x95\xd4\x66\x8c\xe6\x5e\xaa\x75\x0f\x8c\x4a\xb1\x78\x1e\x0a\x3d\x95\x9c\xd1\x4d\x0f\x2e\x79\xaa\x0d\xaa\x3f\x99\xd2\xe6\x27\x33\xab\x7f\xe6\x22\xc5\xc4\x53\x07\x31\x1d\x0d\x80\x69\x07\x00\x46\xc2\xc7\x8b\x4f\x80\x82\x04\x1c\xe1\xee\x46\xdb\x27\x3a\x55\x19\xcb\x70\xab\x07\x50\x29\x0c\x61\x02\x15\x28\xd4\x86\xa8\x1d\xdc\x47\x23\x21\x40\xa0\x2b\xa4\x6b\x0c\x3f\x01\x11\x21\x7c\xfc\xfc\xc9\x82\x14\x90\x66\x85\x90\x6a\x04\xb9\x04\xa1\x51\x18\x54\xc0\x04\x30\xc1\x2a\xb0\x15\xf3\xa6\xa3\x41\xcd\xb4\x53\x08\xa4\x34\xda\x28\x92\x40\xa2\x24\xc5\x30\x55\x08\x02\x31\x74\x9a\x52\x85\xc4\x20\x10\x8b\xb5\x64\x51\x4c\x12\x8b\x5e\x09\xcf\x2e\x6a\x05\xa0\x46\x95\x31\x8a\x7d\x4a\x65\x2a\xcc\xb8\x16\x96\x72\x4d\x29\xf8\xc6\x86\x03\xee\x0a\x0f\x24\x32\xd4\x20\x85\xb3\x46\xc8\x10\x35\xdc\x33\xb3\xb2\x19\xa5\xc8\x2c\x0f\xdb\x3f\xb6\xde\x72\x61\x2d\xa0\xc8\x72\x69\x4d\xdd\xec\x82\x6c\xa5\xfb\xad\xa7\x00\x0a\xff\x9d\x32\x85\xe1\x20\x55\x4c\x44\x73\xba\xc2\x30\xe5\x4c\x44\xa3\x48\xc8\xf2\xf1\xf0\x01\x69\x6a\x6c\x32\x57\x24\x73\xcc\x39\x72\xa4\x46\xaa\x5b\x54\xb1\xae\x0f\x7b\x10\x13\x43\x57\xc3\x87\x44\xa1\x76\xf9\x5f\x1f\xb7\x33\xd6\xb8\xe9\xd5\xcc\x69\xcc\x00\x90\x09\x2a\x62\xa4\xea\xc1\x48\xb4\x06\x33\xc2\x53\x6c\xc1\x5a\xe0\x86\x6f\xad\xdd\x97\xdb\xb8\x97\x02\xa7\x70\xbb\xc2\x46\x52\x00\x95\x09\x43\xbd\x05\xf8\xa0\x61\xc9\xf1\x21\x93\x3c\x8d\x11\x42\xc5\xb2\x32\x6f\x4e\x6d\x26\xd8\xc8\x84\xb8\x24\x29\x37\x2e\xfe\x2e\x6a\x3c\x8d\x98\x80\x90\x29\x97\x98\x28\x74\xaa\x50\x83\x59\x91\x5d\x06\x3b\x39\xa6\x9c\xef\xec\x72\x36\xb5\x30\x84\x60\x03\x9c\x05\x76\x6d\xf8\xbf\x72\x1f\xe0\x03\xd3\x66\x9b\x06\x36\x5b\x4f\xb6\x56\xe6\xdb\x3b\x51\x98\x10\x85\x9e\x8d\x47\xe9\x0a\x16\x93\x08\x7b\x10\x33\x45\x84\x61\xda\xaf\xd7\x80\x62\x7c\x9a\x72\xbe\xdd\xc2\xa3\xe5\x58\x9a\xa9\x42\xbb\x5b\xca\x59\x54\xc6\x31\x11\xe1\xce\xc3\x1e\xf8\xd5\xe5\xce\xf4\xaa\x1c\xca\x7d\x74\x63\xf3\x5b\x57\x05\x72\x25\xd7\x5f\xb5\xb7\xf3\xa4\x97\xfb\x48\x7b\x21\x53\x95\xe8\xc5\x56\x78\x4a\xcc\xaa\x07\x7e\xe1\x4d\xaf\x2e\xd0\xc2\x55\xa9\x68\x01\x28\x99\x90\x88\xb8\x84\x85\x6f\x2c\x77\x33\x93\x82\xf0\x3d\x4b\x55\x31\xb6\xb8\xa1\xa4\x6b\x54\x5a\xd2\xf5\x1e\xa1\x8c\x28\x2b\xe8\xe7\x13\xcf\x6a\x33\xb7\x20\x5c\x46\x7b\xa4\x6d\x18\xab\xa3\xa7\xb0\x94\x2a\x4f\x15\x26\x22\x97\x2b\xf9\x12\x9c\x05\x7e\x91\x12\xbe\x8b\x99\xce\xf3\xc1\xd5\x85\x5a\xc4\xb7\x8b\x66\x44\x79\x9c\x05\x07\x16\xf6\x9a\x53\x4a\xa3\x31\xdb\x23\x56\x1d\xf1\x5a\x7e\xb0\x4a\x36\x13\xac\xbb\xf9\xd8\x4a\x48\x53\xc5\xcc\xc6\x6e\x47\x7c\x30\xd5\xcd\x9b\x28\x96\x31\x8e\x11\x86\xb5\x62\x0c\x80\x22\x6b\x67\xd4\xf7\x1f\xdf\x86\x8b\xf1\x64\x30\x5c\x8c\xfb\x37\xc3\x0a\x8c\xab\x0a\x7f\x2a\x19\xd7\x0b\xc3\x92\x21\x0f\x67\xb8\x6c\x96\x8b\x6a\xaf\xce\x2e\x1a\x83\x4e\x28\xb7\xd4\xb6\xc4\x33\xeb\x71\x5b\xbd\x5b\xda\xdc\x8d\x66\xb7\xd7\xc3\xdb\xc5\x60\x34\xef\x7f\xbb\x1e\x2e\xbe\xdf\xdd\x3c\xae\x52\xde\x3e\x6e\x48\xf2\x1d\x37\x1d\x9a\xd5\x1c\xe8\xe5\x93\x1b\x53\x5c\x01\x0d\x99\xb6\x4d\x6f\xb1\xce\xe2\xc6\xb0\x4c\xf2\xc4\x6f\xf8\xb3\xa9\xf4\x7c\x36\x9a\xdc\x2d\xe6\x3f\xa6\xd3\xc9\xec\xf6\xdd\xd4\xd6\x8a\xc9\x6c\xa1\xd3\x24\x91\xca\x3c\x4f\xf1\xc1\xe4\xe7\xf8\x7a\xd2\x1f\x2c\xa6\xb3\xc9\xed\xe4\x72\x72\xfd\x7e\x3e\x97\xf7\x82\x4b\x12\x2e\x12\x25\x8d\xa4\x92\x3f\xcf\x80\xeb\xc9\xd5\xf5\xf0\x6e\xf8\x7e\x7a\x73\x19\x71\xcc\xf0\x99\xea\x5e\xf6\xaf\x47\x97\x93\xc5\xfc\xc7\xb7\xf1\xf0\xfd\x12\x85\x12\xce\xa8\xf4\x74\x1a\x08\x7c\x62\xa2\x8c\x6e\xfa\x57\xc3\xc5\x6c\x78\x35\xfc\x6b\xba\xb8\x9d\xf5\xc7\xf3\xeb\xfe\xed\x68\x32\x7e\x37\xdd\x5d\xcd\x5e\x28\x8c\xf0\x21\x59\x18\x45\x84\xe6\xae\x33\x3d\xcf\xff\xb3\xfe\xcf\xc5\x60\x78\x37\xba\x1c\xce\xdf\xcd\x02\x45\xee\x17\x21\x5a\xf6\xaa\x9f\xb9\x49\x8b\x92\x78\x3d\xb9\xba\x1a\x8d\xaf\xde\xbd\x2c\x72\x19\x45\x4c\x34\xa7\x1c\xa9\x7c\x9e\x40\x95\xcc\x99\x2f\x06\xa3\x59\xd3\x86\x1e\xf8\x68\xe8\xb6\x07\x16\x8d\x7a\x4b\x3e\x69\x8b\x78\x96\xfc\x20\x6f\xec\x47\x93\xb6\x53\x18\x09\xa0\x44\x23\xdc\x5b\xde\xfa\x2f\xa4\x06\xb8\xa4\x84\x97\x5c\xd1\x21\xd8\xd1\x7b\x22\x8c\x25\xa8\xf6\x10\xc4\x0c\x08\x69\x40\x2e\x97\x8c\x32\xc2\xf9\x06\x48\x46\x18\x77\x07\x25\x29\xf0\x15\x38\x61\x61\xc8\x31\x74\xb0\xca\x1d\xf4\x46\xfb\x4b\xed\xd3\x48\xc9\x34\x69\x31\x87\xc6\xe3\xba\xa8\xa5\x1c\xb1\x0c\x53\x5e\xcb\xca\x5c\xb0\xfd\x5c\x21\x09\x27\x82\x6f\x5a\xc1\xae\x42\xda\x23\x5f\x0b\xab\xf1\xf0\x28\xa0\x3a\x27\x7d\x09\x4f\x7d\x19\xd5\xea\x96\x6e\x26\x1d\xec\x49\xc6\xb6\xb4\xa5\xbb\x8f\x48\x7b\x96\x07\xa3\xd1\x95\x94\xb5\xa7\x16\x2e\x23\x77\x1e\x62\xe5\x49\x67\x85\x0a\x21\x40\x4a\xdc\x29\xdd\xac\x50\xdd\x33\x8d\xe5\xe9\xe7\x9e\x71\x6e\x4f\xde\x61\x4a\x11\x50\x29\xa9\xaa\x90\x9c\xad\xed\x11\x9f\x55\x12\xeb\x14\x7e\x14\x27\x7f\x69\x0f\x44\x5e\x71\x44\xa7\x2b\xa2\x42\xcc\x60\xc9\x38\xc2\x87\xdc\x07\x32\xf2\xb3\x58\xfb\x64\x19\x7e\xf9\x3d\x08\x02\xef\x2b\xfe\xf1\xc5\xbb\xb8\xc0\x2f\xde\x1f\xbf\xff\xed\xc2\x3b\xff\xfc\xff\x9f\xcf\x09\x3d\x3f\x3f\x3f\xff\xec\x53\xa6\x94\xd4\x5e\x16\x2f\xce\xcf\xb8\x8c\x3e\xf4\x60\x2c\x41\xa7\x74\x95\x23\x4a\x55\x9e\xe2\x36\x6d\x22\x1e\x6b\x6f\xff\x09\xa0\xa2\x4a\xfb\xdc\x50\x38\xf3\x71\xe9\x76\xd0\x9e\xc2\xe4\x9f\xc3\xc5\xed\x0e\x60\x02\xb5\x9e\x2a\x19\x60\x55\x04\x1f\x76\x77\x46\xf9\xa7\x55\x2a\x72\x15\xfd\x80\x09\xbf\x52\x2a\xf2\xa7\x1e\x6d\x3c\xd0\x92\x12\x03\x1e\xfc\x18\x8f\xfe\xea\x35\x13\xd0\xaf\x26\x9c\xa7\x24\xfc\xdd\x5a\xe6\x8b\x94\xf3\x46\x91\xed\x3c\xf9\xfe\xaf\x17\xd9\x63\xaa\xe7\xeb\x95\x99\xd3\xbc\xf8\xb9\xeb\x8a\x6a\x65\x05\xa2\xb0\xbc\x22\x82\x60\x03\x3a\x4d\x50\xc5\x4c\xfc\x82\x45\xf9\x57\x2c\x9e\x75\x94\x54\x3b\x1d\xec\x36\x73\xb7\x23\x4a\xa0\x41\x5d\x5e\x94\x14\x37\x24\x7e\x9e\x3a\xbe\x9d\xd6\x5a\xe8\x88\x5b\x98\x6e\xbb\x8b\x45\xfc\x44\x86\xed\xd0\x5a\x54\x3b\xd0\x79\x9b\x73\x4c\x93\x7b\x7e\xbd\xac\xce\xe8\x60\x60\x4d\x4d\xdd\x63\xcf\x7e\xf7\x2a\x5c\xbc\x5d\x80\x9d\x35\x8f\xeb\x52\xf3\xc6\xaf\x54\x4c\x6d\x32\x16\xae\x72\x37\x57\x07\xaa\x67\xc5\xdd\x6f\x77\xa7\x98\xc5\xfa\xa9\xdc\xf1\xbd\xf7\xf3\x4b\x7b\xfa\xb1\x77\x6b\xfb\xaa\xe5\xe1\x3a\x9b\x7b\xac\x72\xb3\x6d\x51\x2b\x74\x6b\x29\x95\xbb\x3a\xb6\xa7\x39\xc8\x4f\x73\x40\x28\x45\xad\xcb\x78\xbb\xff\x41\x2c\x7e\x35\x71\xdb\x1a\x36\xad\x39\x28\xd8\x4d\xf0\x3b\xe8\xfd\x41\x94\xae\xb6\xd2\xe5\xa6\x83\x20\xb5\x9e\xd1\x6a\x23\x07\x45\xab\x4d\xb5\xd9\x66\x4f\xe1\x76\x32\x98\xf4\x20\x94\xe2\x83\x01\xcb\x36\xa9\x0c\xb1\xb8\x3e\x86\xbc\xa0\x3b\xfa\x60\x0b\x8d\x63\xbd\x3b\xc1\x15\xd3\x39\xd1\x2d\x5a\x2c\x5c\xce\x46\x96\xf4\x3e\x6c\x80\x09\x6d\x08\xcf\xcb\x93\x65\x18\xd5\x05\x99\xc8\x43\xe9\x32\x62\xf7\x4f\xd3\xd9\x31\xa6\x1c\xba\xb5\xde\x73\xf1\xfd\x28\x5e\xd7\x2e\xec\xda\x83\x47\x01\x35\x37\x5e\xd7\x76\x7c\x1c\xa8\xb2\x43\x9b\x37\xf1\x07\x85\x5f\xd0\x62\x8f\x6c\xb0\x47\x39\xa1\xb3\xdb\xee\xed\xb5\xc7\x40\x36\x03\x53\xfb\x03\xe0\x18\x7f\x96\x9d\xb5\x5a\xdb\xba\x6a\xe2\x51\x60\x07\xa3\xfc\x14\xb0\x2e\x56\x75\x88\x53\x1d\xa5\x5d\x87\xdb\x1b\x84\xe0\x28\xbd\x04\x1a\xd1\xc4\x71\xcf\x6a\xb1\x2b\x2f\xbb\x7a\xfb\x5a\x98\x97\xb3\x96\x4e\xc2\x72\x98\xd6\x34\x5f\x45\x50\x01\xa1\x67\x24\x35\x2b\xa9\xd8\x7f\xdc\x9c\xb3\xf5\x57\x7d\xc6\x64\xe3\xcd\x84\xe2\xef\xfc\x99\xe4\xf8\x8d\x89\x90\x89\xe8\xc0\x2b\x0a\x4a\x72\x2c\x6e\xe9\x48\xc2\xae\x6c\x51\x3f\xb0\xd2\x09\x40\x6b\x8d\x16\xa4\x4e\x03\x7b\xec\xd2\xbd\x13\xaf\x98\x3d\xaf\xfd\x7f\x7e\xfc\x6b\x12\xd6\x03\xed\xf5\x9e\xe6\x93\x67\xbc\x9d\xa1\x6c\x57\xb2\xf3\xbd\xd2\x27\x95\xcb\xbf\xdf\x7e\x73\x5f\x15\x6a\x99\x2a\x8a\x95\x91\xf2\x7d\x82\x3c\xc2\x19\xaa\xa0\x3a\xea\xee\x34\x5e\x23\xaa\x1d\x36\x95\x4b\x7b\x96\x94\xa2\xda\xda\xd0\xb0\xa0\xd0\xbe\xa6\x7b\x43\xef\x52\x6b\x0f\x22\xe7\x24\x0f\x38\xd3\xf9\x97\x7b\x62\xe8\xea\x8d\x2c\xd8\x6e\x97\x54\xa3\xb2\x23\x2f\x36\xc4\xb3\x9c\x5e\xe5\xc5\xa3\x61\xd4\x9b\xee\xac\x6d\xbb\x11\x32\x44\x2f\x28\xa6\xbd\xe2\x36\x6b\x85\xba\xba\xdf\x9e\x02\x7e\x55\x30\xb8\x1c\x36\xcf\xfd\x9e\x7b\x51\xe5\x8d\x4b\x4f\xbc\x0b\xf2\x1b\xf8\x67\x5f\x22\xfd\x22\x65\xc9\xa3\x2a\x7c\xac\x02\x91\x84\xed\xde\x4b\x2b\x90\xf7\x57\xa5\x54\x1b\x19\x6f\x07\x42\x74\xaf\x11\x95\x6d\xa8\xbb\x48\xed\x5b\x78\x7b\xea\x5c\x7f\xd5\x7b\xd7\x2b\xe6\xb8\xae\x16\x93\x24\x61\x22\xea\x5c\xaa\xa8\x2a\xf9\x8f\x37\xdf\x95\x35\xef\xbe\x7e\xb2\x59\xd8\xd7\x4d\xb0\xc6\x8b\x0d\x9d\x80\xcf\xe8\x6d\xff\x0d\x00\x00\xff\xff\x89\x01\x83\x3e\xe0\x28\x00\x00") func deployDataVirtletDsYamlBytes() ([]byte, error) { return bindataRead( @@ -81,7 +81,7 @@ func deployDataVirtletDsYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "deploy/data/virtlet-ds.yaml", size: 10825, mode: os.FileMode(420), modTime: time.Unix(1522279343, 0)} + info := bindataFileInfo{name: "deploy/data/virtlet-ds.yaml", size: 10464, mode: os.FileMode(420), modTime: time.Unix(1522279343, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/pkg/tools/kubeclient.go b/pkg/tools/kubeclient.go index 768e16824..4692c797f 100644 --- a/pkg/tools/kubeclient.go +++ b/pkg/tools/kubeclient.go @@ -220,7 +220,7 @@ func (c *RealKubeClient) setup() error { client, err := kubernetes.NewForConfig(config) if err != nil { - return fmt.Errorf("Can't create kubernetes api client: %v", err) + return fmt.Errorf("can't create kubernetes api client: %v", err) } ns, _, err := c.clientCfg.Namespace() diff --git a/pkg/tools/settings.go b/pkg/tools/settings.go index 18bb448ee..0bd3b2412 100644 --- a/pkg/tools/settings.go +++ b/pkg/tools/settings.go @@ -17,12 +17,13 @@ limitations under the License. package tools import ( - "flag" "os" + "strings" "github.com/spf13/pflag" "k8s.io/client-go/tools/clientcmd" - "strings" + + "github.com/Mirantis/virtlet/pkg/utils" ) const ( @@ -33,36 +34,6 @@ var ( virtletRuntime = defaultVirtletRuntimeName ) -// wordSepNormalizeFunc change "_" to "-" in the flags. -func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - if strings.Contains(name, "_") { - return pflag.NormalizedName(strings.Replace(name, "_", "-", -1)) - } - return pflag.NormalizedName(name) -} - -// defaultClientConfig builds a default Kubernetes client config based -// on Cobra flags. It's based on kubelet code. -func defaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - // use the standard defaults for this client command - // DEPRECATED: remove and replace with something more accurate - loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig - - flags.StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") - - overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} - - flagNames := clientcmd.RecommendedConfigOverrideFlags("") - // short flagnames are disabled by default. These are here for compatibility with existing scripts - flagNames.ClusterOverrideFlags.APIServer.ShortName = "s" - - clientcmd.BindOverrideFlags(overrides, flags, flagNames) - clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin) - - return clientConfig -} - // from k8s pkg/kubectl/plugins/env.go func flagToEnvName(flagName, prefix string) string { envName := strings.TrimPrefix(flagName, "--") @@ -76,9 +47,7 @@ func flagToEnvName(flagName, prefix string) string { // flag values from kubectl plugin environment variables in case if // virtletctl is running as a kubectl plugin. func BindFlags(flags *pflag.FlagSet) clientcmd.ClientConfig { - flags.AddGoFlagSet(flag.CommandLine) - flags.SetNormalizeFunc(wordSepNormalizeFunc) - clientConfig := defaultClientConfig(flags) + clientConfig := utils.BindFlags(flags) flags.StringVar(&virtletRuntime, "virtlet-runtime", defaultVirtletRuntimeName, "the name of virtlet runtime used in kubernetes.io/target-runtime annotation") if InPlugin() { for _, flagName := range []string{ diff --git a/pkg/tools/version.go b/pkg/tools/version.go index f59e6b55a..3815d6240 100644 --- a/pkg/tools/version.go +++ b/pkg/tools/version.go @@ -82,7 +82,7 @@ func (v *versionCommand) getVersions() (version.ClusterVersionInfo, error) { exitCode, err := v.client.ExecInContainer( podName, "virtlet", "kube-system", nil, &buf, os.Stderr, - []string{"virtlet", "-version", "-version-format", "json"}) + []string{"virtlet", "--version", "--version-format", "json"}) switch { case err != nil: errors = append(errors, fmt.Sprintf("node %q: error getting version from Virtlet pod %q: %v", nodeName, podName, err)) diff --git a/pkg/tools/version_test.go b/pkg/tools/version_test.go index 362bfb9dd..dc729d4bf 100644 --- a/pkg/tools/version_test.go +++ b/pkg/tools/version_test.go @@ -88,8 +88,8 @@ func TestVersionCommand(t *testing.T) { "kube-node-2": "virtlet-bar42", }, expectedCommands: map[string]string{ - "virtlet-foo42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), - "virtlet-bar42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-foo42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-bar42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), }, }, { @@ -103,8 +103,8 @@ func TestVersionCommand(t *testing.T) { "kube-node-2": "virtlet-bar42", }, expectedCommands: map[string]string{ - "virtlet-foo42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), - "virtlet-bar42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-foo42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-bar42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), }, }, { @@ -115,8 +115,8 @@ func TestVersionCommand(t *testing.T) { "kube-node-2": "virtlet-bar42", }, expectedCommands: map[string]string{ - "virtlet-foo42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), - "virtlet-bar42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-foo42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-bar42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), }, wrap: func(bs []byte) gm.Verifier { return gm.NewJSONVerifier(bs) }, }, @@ -128,8 +128,8 @@ func TestVersionCommand(t *testing.T) { "kube-node-2": "virtlet-bar42", }, expectedCommands: map[string]string{ - "virtlet-foo42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), - "virtlet-bar42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-foo42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-bar42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), }, wrap: func(bs []byte) gm.Verifier { return gm.NewYamlVerifier(bs) }, }, @@ -174,8 +174,8 @@ func TestVersionCommand(t *testing.T) { "kube-node-2": "virtlet-bar42", }, expectedCommands: map[string]string{ - "virtlet-foo42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo), - "virtlet-bar42/virtlet/kube-system: virtlet -version -version-format json": versionInfoToString(nodeVersionInfo1), + "virtlet-foo42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo), + "virtlet-bar42/virtlet/kube-system: virtlet --version --version-format json": versionInfoToString(nodeVersionInfo1), }, errSubstring: "some of the nodes have inconsistent Virtlet builds", }, diff --git a/pkg/utils/k8s_client.go b/pkg/utils/k8s_client.go index 414a487d8..e525622c1 100644 --- a/pkg/utils/k8s_client.go +++ b/pkg/utils/k8s_client.go @@ -17,13 +17,17 @@ limitations under the License. package utils import ( + "flag" "os" + "strings" + "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" ) // GetK8sClientConfig returns config that is needed to access k8s @@ -64,3 +68,41 @@ func GetK8sRestClient(cfg *rest.Config, scheme *runtime.Scheme, groupVersion *sc } return client, nil } + +// wordSepNormalizeFunc change "_" to "-" in the flags. +func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + if strings.Contains(name, "_") { + return pflag.NormalizedName(strings.Replace(name, "_", "-", -1)) + } + return pflag.NormalizedName(name) +} + +// defaultClientConfig builds a default Kubernetes client config based +// on Cobra flags. It's based on kubelet code. +func defaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + // use the standard defaults for this client command + // DEPRECATED: remove and replace with something more accurate + loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig + + flags.StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") + + overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} + + flagNames := clientcmd.RecommendedConfigOverrideFlags("") + // short flagnames are disabled by default. These are here for compatibility with existing scripts + flagNames.ClusterOverrideFlags.APIServer.ShortName = "s" + + clientcmd.BindOverrideFlags(overrides, flags, flagNames) + clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin) + + return clientConfig +} + +// BindFlags applies standard Go flags and the flags used by kubeclient +// to the specified FlagSet. +func BindFlags(flags *pflag.FlagSet) clientcmd.ClientConfig { + flags.AddGoFlagSet(flag.CommandLine) + flags.SetNormalizeFunc(wordSepNormalizeFunc) + return defaultClientConfig(flags) +} diff --git a/tests/e2e/framework/controller.go b/tests/e2e/framework/controller.go index 00b1cb641..6d5f2d9c2 100644 --- a/tests/e2e/framework/controller.go +++ b/tests/e2e/framework/controller.go @@ -28,7 +28,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/types/v1" + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" ) var ClusterURL = flag.String("cluster-url", "http://127.0.0.1:8080", "apiserver URL") diff --git a/tests/e2e/image_name_translation_test.go b/tests/e2e/image_name_translation_test.go index d5b560f08..6ebb8fa07 100644 --- a/tests/e2e/image_name_translation_test.go +++ b/tests/e2e/image_name_translation_test.go @@ -22,7 +22,7 @@ import ( . "github.com/onsi/gomega" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/types/v1" + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" . "github.com/Mirantis/virtlet/tests/e2e/ginkgo-ext" ) @@ -45,7 +45,7 @@ var _ = Describe("Image URL", func() { }) Expect(err).NotTo(HaveOccurred()) - vimName = vim.Name() + vimName = vim.Name }) AfterAll(func() { diff --git a/tests/integration/manager.go b/tests/integration/manager.go index 98b9b78f7..82db6296e 100644 --- a/tests/integration/manager.go +++ b/tests/integration/manager.go @@ -29,12 +29,15 @@ import ( "google.golang.org/grpc" + "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "github.com/Mirantis/virtlet/pkg/config" "github.com/Mirantis/virtlet/pkg/manager" "github.com/Mirantis/virtlet/pkg/tapmanager" ) const ( - virtletSocket = "/tmp/virtlet.sock" + virtletSocket = "/tmp/virtlet.sock" + disableKvmEnvVar = "VIRTLET_DISABLE_KVM" ) type fakeFDManager struct{} @@ -107,17 +110,21 @@ func (v *VirtletManager) Run() { } os.Setenv("KUBERNETES_CLUSTER_URL", "") - v.manager = manager.NewVirtletManager(&manager.VirtletConfig{ - FDManager: &fakeFDManager{}, - DatabasePath: filepath.Join(v.tempDir, "virtlet.db"), - DownloadProtocol: "http", - ImageDir: filepath.Join(v.tempDir, "images"), - SkipImageTranslation: true, - LibvirtURI: libvirtURI, - RawDevices: "loop*", - CRISocketPath: virtletSocket, - DisableLogging: true, + pstr := func(s string) *string { return &s } + pbool := func(b bool) *bool { return &b } + cfg := config.GetDefaultConfig() + config.Override(cfg, &v1.VirtletConfig{ + DatabasePath: pstr(filepath.Join(v.tempDir, "virtlet.db")), + DownloadProtocol: pstr("http"), + ImageDir: pstr(filepath.Join(v.tempDir, "images")), + SkipImageTranslation: pbool(true), + LibvirtURI: pstr(libvirtURI), + RawDevices: pstr("loop*"), + CRISocketPath: pstr(virtletSocket), + DisableLogging: pbool(true), + DisableKVM: pbool(os.Getenv(disableKvmEnvVar) != ""), }) + v.manager = manager.NewVirtletManager(cfg, &fakeFDManager{}) v.doneCh = make(chan struct{}) go func() { if err := v.manager.Run(); err != nil { diff --git a/tests/network/vm_network_test.go b/tests/network/vm_network_test.go index 30cf1a6f5..c51ddaef8 100644 --- a/tests/network/vm_network_test.go +++ b/tests/network/vm_network_test.go @@ -252,7 +252,7 @@ func TestVmNetwork(t *testing.T) { if err != nil { return fmt.Errorf("LinkList() failed: %v", err) } - csn, err = nettools.SetupContainerSideNetwork(info, contNS.Path(), allLinks) + csn, err = nettools.SetupContainerSideNetwork(info, contNS.Path(), allLinks, false) if err != nil { return fmt.Errorf("failed to set up container side network: %v", err) } @@ -338,7 +338,7 @@ func (tst *tapFDSourceTester) setupServerAndConnectToFDServer() *tapmanager.FDCl tst.t.Fatalf("the server and/or the client is already present") } - src, err := tapmanager.NewTapFDSource(tst.cniClient) + src, err := tapmanager.NewTapFDSource(tst.cniClient, false, 24) if err != nil { tst.t.Fatalf("Error creating tap fd source: %v", err) } From c793f9c6e1a09d92ee6931789911554fc9f34b28 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Thu, 7 Jun 2018 05:10:36 +0300 Subject: [PATCH 03/17] Use new-style client for image translation CRDs --- cmd/virtlet/virtlet.go | 7 +- pkg/api/virtlet.k8s/v1/client.go | 28 ------- pkg/config/config.go | 2 +- pkg/imagetranslation/crd_source.go | 60 ++++++++------ pkg/imagetranslation/crd_source_test.go | 102 ++++++++++++++++++++++++ pkg/imagetranslation/translator.go | 7 +- pkg/manager/manager.go | 6 +- pkg/utils/k8s_client.go | 18 ----- tests/e2e/framework/controller.go | 47 ++++------- tests/integration/manager.go | 2 +- 10 files changed, 168 insertions(+), 111 deletions(-) delete mode 100644 pkg/api/virtlet.k8s/v1/client.go create mode 100644 pkg/imagetranslation/crd_source_test.go diff --git a/cmd/virtlet/virtlet.go b/cmd/virtlet/virtlet.go index 4625c1c80..e7a8a05d6 100644 --- a/cmd/virtlet/virtlet.go +++ b/cmd/virtlet/virtlet.go @@ -24,6 +24,7 @@ import ( "github.com/golang/glog" flag "github.com/spf13/pflag" + "k8s.io/client-go/tools/clientcmd" "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/cni" @@ -52,8 +53,8 @@ func configWithDefaults(cfg *v1.VirtletConfig) *v1.VirtletConfig { return r } -func runVirtlet(config *v1.VirtletConfig) { - manager := manager.NewVirtletManager(config, nil) +func runVirtlet(config *v1.VirtletConfig, clientCfg clientcmd.ClientConfig) { + manager := manager.NewVirtletManager(config, nil, clientCfg) if err := manager.Run(); err != nil { glog.Errorf("Error: %v", err) os.Exit(1) @@ -141,6 +142,6 @@ func main() { default: localConfig = configWithDefaults(localConfig) startTapManagerProcess(localConfig) - runVirtlet(localConfig) + runVirtlet(localConfig, clientCfg) } } diff --git a/pkg/api/virtlet.k8s/v1/client.go b/pkg/api/virtlet.k8s/v1/client.go deleted file mode 100644 index 986441489..000000000 --- a/pkg/api/virtlet.k8s/v1/client.go +++ /dev/null @@ -1,28 +0,0 @@ -/* -Copyright 2018 Mirantis - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or ≈git-agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "k8s.io/client-go/rest" - - "github.com/Mirantis/virtlet/pkg/utils" -) - -// GetCRDRestClient returns ReST client that can be used to work with virtlet CRDs -func GetCRDRestClient(cfg *rest.Config) (*rest.RESTClient, error) { - return utils.GetK8sRestClient(cfg, scheme, &SchemeGroupVersion) -} diff --git a/pkg/config/config.go b/pkg/config/config.go index f333ce38d..a7686c6d9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -22,11 +22,11 @@ import ( virtletclient "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" flag "github.com/spf13/pflag" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( diff --git a/pkg/imagetranslation/crd_source.go b/pkg/imagetranslation/crd_source.go index bd0e04d66..72d260475 100644 --- a/pkg/imagetranslation/crd_source.go +++ b/pkg/imagetranslation/crd_source.go @@ -20,54 +20,62 @@ import ( "context" "fmt" - "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" - "github.com/Mirantis/virtlet/pkg/utils" + "k8s.io/client-go/tools/clientcmd" + + virtletclient "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type crdConfigSource struct { - namespace string + clientCfg clientcmd.ClientConfig + virtletClient virtletclient.Interface + namespace string } -var _ ConfigSource = crdConfigSource{} +var _ ConfigSource = &crdConfigSource{} -// Configs implements ConfigSource Configs -func (cs crdConfigSource) Configs(ctx context.Context) ([]TranslationConfig, error) { - cfg, err := utils.GetK8sClientConfig("") - if err != nil { - return nil, err +func (cs *crdConfigSource) setup() error { + if cs.virtletClient != nil { + return nil } - if cfg.Host == "" { - return nil, nil + config, err := cs.clientCfg.ClientConfig() + if err != nil { + return err } - client, err := v1.GetCRDRestClient(cfg) + virtletClient, err := virtletclient.NewForConfig(config) if err != nil { + return fmt.Errorf("can't create Virtlet api client: %v", err) + } + cs.virtletClient = virtletClient + return nil +} + +// Configs implements ConfigSource Configs +func (cs *crdConfigSource) Configs(ctx context.Context) ([]TranslationConfig, error) { + if err := cs.setup(); err != nil { return nil, err } - var list v1.VirtletImageMappingList - err = client.Get(). - Context(ctx). - Resource("virtletimagemappings"). - Namespace(cs.namespace). - Do().Into(&list) + + list, err := cs.virtletClient.VirtletV1().VirtletImageMappings(cs.namespace).List(meta_v1.ListOptions{}) if err != nil { return nil, err } - result := make([]TranslationConfig, len(list.Items)) - for i, v := range list.Items { - result[i] = &v - } - return result, nil + var r []TranslationConfig + for n := range list.Items { + r = append(r, &list.Items[n]) + } + return r, nil } // Description implements ConfigSource Description -func (cs crdConfigSource) Description() string { +func (cs *crdConfigSource) Description() string { return fmt.Sprintf("Kubernetes VirtletImageMapping resources in namespace %q", cs.namespace) } // NewCRDSource is a factory for CRD-based config source -func NewCRDSource(namespace string) ConfigSource { - return crdConfigSource{namespace: namespace} +func NewCRDSource(namespace string, clientCfg clientcmd.ClientConfig) ConfigSource { + return &crdConfigSource{namespace: namespace, clientCfg: clientCfg} } diff --git a/pkg/imagetranslation/crd_source_test.go b/pkg/imagetranslation/crd_source_test.go new file mode 100644 index 000000000..a91f345dc --- /dev/null +++ b/pkg/imagetranslation/crd_source_test.go @@ -0,0 +1,102 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package imagetranslation + +import ( + "context" + "reflect" + "strings" + "testing" + + "github.com/ghodss/yaml" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/fake" +) + +func TestCRDConfigSource(t *testing.T) { + srcConfigs := []*virtlet_v1.VirtletImageMapping{ + { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "mapping1", + Namespace: "foobar", + }, + Spec: virtlet_v1.ImageTranslation{ + Rules: []virtlet_v1.TranslationRule{ + { + Name: "testimage1", + URL: "https://example.com/testimage1.qcow2", + }, + }, + }, + }, + { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "mapping2", + Namespace: "foobar", + }, + Spec: virtlet_v1.ImageTranslation{ + Rules: []virtlet_v1.TranslationRule{ + { + Name: "testimage2", + URL: "https://example.com/testimage2.qcow2", + }, + }, + }, + }, + { + ObjectMeta: meta_v1.ObjectMeta{ + Name: "mapping3_skipme", + Namespace: "skipthisns", + }, + Spec: virtlet_v1.ImageTranslation{ + Rules: []virtlet_v1.TranslationRule{ + { + Name: "testimage3_skipme", + URL: "https://example.com/nosuchimage.qcow2", + }, + }, + }, + }, + } + clientset := fake.NewSimpleClientset(srcConfigs[0], srcConfigs[1], srcConfigs[2]) + cs := NewCRDSource("foobar", nil) + cs.(*crdConfigSource).virtletClient = clientset + + desc := cs.Description() + if !strings.Contains(desc, "foobar") { + t.Errorf("Namespace name 'foobar' not in CRD source description: %q", desc) + } + + expectedConfigs := []TranslationConfig{srcConfigs[0], srcConfigs[1]} + configs, err := cs.Configs(context.Background()) + if err != nil { + t.Fatalf("Configs(): %v", err) + } + if !reflect.DeepEqual(expectedConfigs, configs) { + expected, err := yaml.Marshal(expectedConfigs) + if err != nil { + t.Errorf("Error marshalling yaml: %v", err) + } + actual, err := yaml.Marshal(configs) + if err != nil { + t.Errorf("Error marshalling yaml: %v", err) + } + t.Errorf("Bad config list.\n--- expected configs ---\n%s\n--- actual configs ---\n%s", expected, actual) + } +} diff --git a/pkg/imagetranslation/translator.go b/pkg/imagetranslation/translator.go index d9bdef84f..5c05d7fcf 100644 --- a/pkg/imagetranslation/translator.go +++ b/pkg/imagetranslation/translator.go @@ -29,6 +29,7 @@ import ( "time" "github.com/golang/glog" + "k8s.io/client-go/tools/clientcmd" "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/image" @@ -202,9 +203,11 @@ func NewImageNameTranslator(allowRegexp bool) ImageNameTranslator { // GetDefaultImageTranslator returns a default image translation that // uses CRDs and a config directory -func GetDefaultImageTranslator(imageTranslationConfigsDir string, allowRegexp bool) image.Translator { +func GetDefaultImageTranslator(imageTranslationConfigsDir string, allowRegexp bool, clientCfg clientcmd.ClientConfig) image.Translator { var sources []ConfigSource - sources = append(sources, NewCRDSource("kube-system")) + if clientCfg != nil { + sources = append(sources, NewCRDSource("kube-system", clientCfg)) + } if imageTranslationConfigsDir != "" { sources = append(sources, NewFileConfigSource(imageTranslationConfigsDir)) } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index c2f2afb35..392198fa1 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -22,6 +22,7 @@ import ( "time" "github.com/golang/glog" + "k8s.io/client-go/tools/clientcmd" "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" "github.com/Mirantis/virtlet/pkg/image" @@ -45,6 +46,7 @@ type VirtletManager struct { config *v1.VirtletConfig metadataStore metadata.Store fdManager tapmanager.FDManager + clientCfg clientcmd.ClientConfig virtTool *libvirttools.VirtualizationTool imageStore image.Store runtimeService *VirtletRuntimeService @@ -53,7 +55,7 @@ type VirtletManager struct { } // NewVirtletManager creates a new VirtletManager. -func NewVirtletManager(config *v1.VirtletConfig, fdManager tapmanager.FDManager) *VirtletManager { +func NewVirtletManager(config *v1.VirtletConfig, fdManager tapmanager.FDManager, clientCfg clientcmd.ClientConfig) *VirtletManager { return &VirtletManager{config: config, fdManager: fdManager} } @@ -90,7 +92,7 @@ func (v *VirtletManager) Run() error { if err = v1.RegisterCustomResourceTypes(); err != nil { return fmt.Errorf("failed to register image translation CRD: %v", err) } - translator = imagetranslation.GetDefaultImageTranslator(*v.config.ImageTranslationConfigsDir, *v.config.EnableRegexpImageTranslation) + translator = imagetranslation.GetDefaultImageTranslator(*v.config.ImageTranslationConfigsDir, *v.config.EnableRegexpImageTranslation, v.clientCfg) } else { translator = imagetranslation.GetEmptyImageTranslator() } diff --git a/pkg/utils/k8s_client.go b/pkg/utils/k8s_client.go index e525622c1..8c9b45f85 100644 --- a/pkg/utils/k8s_client.go +++ b/pkg/utils/k8s_client.go @@ -22,9 +22,6 @@ import ( "strings" "github.com/spf13/pflag" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -54,21 +51,6 @@ func GetK8sClientset(config *rest.Config) (*kubernetes.Clientset, error) { return kubernetes.NewForConfig(config) } -// GetK8sRestClient returns k8s ReST client that for the giver API group-version/subset -func GetK8sRestClient(cfg *rest.Config, scheme *runtime.Scheme, groupVersion *schema.GroupVersion) (*rest.RESTClient, error) { - config := *cfg - config.GroupVersion = groupVersion - config.APIPath = "/apis" - config.ContentType = runtime.ContentTypeJSON - config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)} - - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return client, nil -} - // wordSepNormalizeFunc change "_" to "-" in the flags. func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { if strings.Contains(name, "_") { diff --git a/tests/e2e/framework/controller.go b/tests/e2e/framework/controller.go index 6d5f2d9c2..4ef315044 100644 --- a/tests/e2e/framework/controller.go +++ b/tests/e2e/framework/controller.go @@ -29,6 +29,7 @@ import ( "k8s.io/client-go/tools/clientcmd" virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + virtletclientv1 "github.com/Mirantis/virtlet/pkg/client/clientset/versioned/typed/virtlet.k8s/v1" ) var ClusterURL = flag.String("cluster-url", "http://127.0.0.1:8080", "apiserver URL") @@ -37,9 +38,10 @@ var ClusterURL = flag.String("cluster-url", "http://127.0.0.1:8080", "apiserver type Controller struct { fixedNs bool - client *typedv1.CoreV1Client - namespace *v1.Namespace - restConfig *restclient.Config + client typedv1.CoreV1Interface + virtletClient virtletclientv1.VirtletV1Interface + namespace *v1.Namespace + restConfig *restclient.Config } // NewController creates instance of controller for specified k8s namespace. @@ -55,6 +57,11 @@ func NewController(namespace string) (*Controller, error) { return nil, err } + virtletClient, err := virtletclientv1.NewForConfig(config) + if err != nil { + return nil, err + } + var ns *v1.Namespace if namespace != "" { ns, err = clientset.Namespaces().Get(namespace, metav1.GetOptions{}) @@ -66,10 +73,11 @@ func NewController(namespace string) (*Controller, error) { } return &Controller{ - client: clientset, - namespace: ns, - restConfig: config, - fixedNs: namespace != "", + client: clientset, + virtletClient: virtletClient, + namespace: ns, + restConfig: config, + fixedNs: namespace != "", }, nil } @@ -92,32 +100,11 @@ func (c *Controller) Finalize() error { } func (c *Controller) CreateVirtletImageMapping(mapping virtlet_v1.VirtletImageMapping) (*virtlet_v1.VirtletImageMapping, error) { - client, err := virtlet_v1.GetCRDRestClient(c.restConfig) - if err != nil { - return nil, err - } - var result virtlet_v1.VirtletImageMapping - err = client.Post(). - Resource("virtletimagemappings"). - Namespace("kube-system"). - Body(&mapping). - Do().Into(&result) - if err != nil { - return nil, err - } - return &result, nil + return c.virtletClient.VirtletImageMappings("kube-system").Create(&mapping) } func (c *Controller) DeleteVirtletImageMapping(name string) error { - client, err := virtlet_v1.GetCRDRestClient(c.restConfig) - if err != nil { - return err - } - return client.Delete(). - Resource("virtletimagemappings"). - Namespace("kube-system"). - Name(name). - Do().Error() + return c.virtletClient.VirtletImageMappings("kube-system").Delete(name, &metav1.DeleteOptions{}) } // PersistentVolumesClient returns interface for PVs diff --git a/tests/integration/manager.go b/tests/integration/manager.go index 82db6296e..92f641fc7 100644 --- a/tests/integration/manager.go +++ b/tests/integration/manager.go @@ -124,7 +124,7 @@ func (v *VirtletManager) Run() { DisableLogging: pbool(true), DisableKVM: pbool(os.Getenv(disableKvmEnvVar) != ""), }) - v.manager = manager.NewVirtletManager(cfg, &fakeFDManager{}) + v.manager = manager.NewVirtletManager(cfg, &fakeFDManager{}, nil) v.doneCh = make(chan struct{}) go func() { if err := v.manager.Run(); err != nil { From 156af633e95bf05d7d314ded2fab9047595a9bdd Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Thu, 7 Jun 2018 21:43:52 +0300 Subject: [PATCH 04/17] Fix erroneous glog.Warning() calls --- cmd/virtlet/virtlet.go | 2 +- pkg/libvirttools/cloudinit.go | 2 +- pkg/manager/manager.go | 2 +- tests/network/utils_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/virtlet/virtlet.go b/cmd/virtlet/virtlet.go index e7a8a05d6..0833a3999 100644 --- a/cmd/virtlet/virtlet.go +++ b/cmd/virtlet/virtlet.go @@ -132,7 +132,7 @@ func main() { nodeName := os.Getenv(nodeNameEnv) cfg, err := nodeConfig.LoadConfig(localConfig, nodeName) if err != nil { - glog.Warning("Failed to load per-node configs, using local config only: %v", err) + glog.Warningf("Failed to load per-node configs, using local config only: %v", err) cfg = localConfig } if _, err := os.Stdout.Write([]byte(config.DumpEnv(cfg))); err != nil { diff --git a/pkg/libvirttools/cloudinit.go b/pkg/libvirttools/cloudinit.go index f4a84ccdb..f211d03a3 100644 --- a/pkg/libvirttools/cloudinit.go +++ b/pkg/libvirttools/cloudinit.go @@ -191,7 +191,7 @@ func (g *CloudInitGenerator) generateNetworkConfigurationNoCloud() ([]byte, erro continue case len(gateways) > 1: gw = gateways[0] - glog.Warning("cloud-init: got more than one gateway and a route with empty gateway, using the first gateway: %q", gw) + glog.Warningf("cloud-init: got more than one gateway and a route with empty gateway, using the first gateway: %q", gw) default: gw = gateways[0] } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 392198fa1..f4476aa0c 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -120,7 +120,7 @@ func (v *VirtletManager) Run() error { err = s.Start() if err != nil { - glog.Warning("Could not start stream server: %s", err) + glog.Warningf("Could not start stream server: %s", err) } streamServer = s diff --git a/tests/network/utils_test.go b/tests/network/utils_test.go index 511c694a7..70d0d3b57 100644 --- a/tests/network/utils_test.go +++ b/tests/network/utils_test.go @@ -536,7 +536,7 @@ func (tc *tapConnector) copyFrames(from, to *os.File) { break } if nWritten < nRead { - glog.Warning("copyFrames(): short Write(): %d bytes instead of %d", nWritten, nRead) + glog.Warningf("copyFrames(): short Write(): %d bytes instead of %d", nWritten, nRead) } } tc.wg.Done() From 6b4ff25eafe9bdac10910b64acd6814ac7223a83 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Thu, 7 Jun 2018 21:44:36 +0300 Subject: [PATCH 05/17] Fix multi-document yaml handling in gm --- tests/gm/data.go | 55 +++++++++++++++++++++++++++++++++++++++++++ tests/gm/data_test.go | 12 ++++++++++ 2 files changed, 67 insertions(+) diff --git a/tests/gm/data.go b/tests/gm/data.go index 44c3960a3..25bb2cb54 100644 --- a/tests/gm/data.go +++ b/tests/gm/data.go @@ -136,8 +136,63 @@ func (v YamlVerifier) Suffix() string { return ".yaml" } +func marshalMultiple(data []interface{}) ([]byte, error) { + var out bytes.Buffer + for _, v := range data { + bs, err := yaml.Marshal(v) + if err != nil { + return nil, err + } + fmt.Fprintf(&out, "---\n%s", bs) + } + return out.Bytes(), nil +} + +func unmarshalMultiple(in []byte) ([]interface{}, error) { + var r []interface{} + for _, part := range bytes.Split(in, []byte("---\n")) { + if len(bytes.TrimSpace(part)) == 0 { + continue + } + var data interface{} + if err := yaml.Unmarshal(part, &data); err != nil { + return nil, err + } + r = append(r, data) + } + return r, nil +} + +func (v YamlVerifier) verifyMultiple(content []byte) (bool, error) { + curData, err := unmarshalMultiple(content) + if err != nil { + glog.Warningf("Failed to unmarshal to YAML: %v:\n%s", err, content) + return false, nil + } + + out, err := v.Marshal() + if err != nil { + return false, err + } + + newData, err := unmarshalMultiple(out) + if err != nil { + return false, fmt.Errorf("failed to unmarshal back marshalled value: %v. YAML:\n%s\nOriginal data:\n%s", + err, string(out), content) + } + + return reflect.DeepEqual(curData, newData), nil +} + // Verify implements Verify method of the Verifier interface. func (v YamlVerifier) Verify(content []byte) (bool, error) { + switch v.data.(type) { + case []byte: + return v.verifyMultiple(content) + case string: + return v.verifyMultiple(content) + } + var curData interface{} if err := yaml.Unmarshal(content, &curData); err != nil { glog.Warningf("Failed to unmarshal to YAML: %v:\n%s", err, content) diff --git a/tests/gm/data_test.go b/tests/gm/data_test.go index 53db74b3a..b9bcedb51 100644 --- a/tests/gm/data_test.go +++ b/tests/gm/data_test.go @@ -179,12 +179,24 @@ func TestData(t *testing.T) { compareWith: NewYamlVerifier("x: 42"), diff: false, }, + { + name: "yaml content (raw comparison, string, multiple docs)", + toWriteRaw: "x: 42\n---\ny: 4242", + compareWith: NewYamlVerifier("x: 43\n---\ny: 4242"), + diff: true, + }, { name: "yaml content with changes (raw comparison, string)", toWriteRaw: "x: 42", compareWith: NewYamlVerifier("x: 43"), diff: true, }, + { + name: "yaml content with changes (raw comparison, string, multiple docs)", + toWriteRaw: "x: 42\n---\ny: 4242", + compareWith: NewYamlVerifier("x: 42\n---\ny: 4243"), + diff: true, + }, { name: "yaml content (raw comparison, []byte)", toWriteRaw: "x: 42", From 053bf8b81d8dae8d4b52a5e7cf50f23207e12bbb Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Thu, 7 Jun 2018 21:46:08 +0300 Subject: [PATCH 06/17] Use virtletctl gen for CRD def generation Standard output includes the CRDs `virtletctl gen --crd` gives CRD-only output Add perms for accessing nodes and CRDs --- deploy/data/virtlet-ds.yaml | 35 +- pkg/api/virtlet.k8s/v1/crd.go | 75 ++++ pkg/api/virtlet.k8s/v1/register.go | 67 +--- pkg/api/virtlet.k8s/v1/virtletconfig.go | 2 +- pkg/manager/manager.go | 3 - pkg/tools/TestGenCommand__compat.out.yaml | 51 +++ pkg/tools/TestGenCommand__compat_dev.out.yaml | 51 +++ pkg/tools/TestGenCommand__crd.out.yaml | 48 +++ pkg/tools/TestGenCommand__dev.out.yaml | 51 +++ pkg/tools/TestGenCommand__plain.out.yaml | 369 ++++++++++-------- pkg/tools/TestGenCommand__tag.out.yaml | 51 +++ pkg/tools/bindata.go | 4 +- pkg/tools/gen.go | 59 +-- pkg/tools/gen_test.go | 4 + 14 files changed, 603 insertions(+), 267 deletions(-) create mode 100644 pkg/api/virtlet.k8s/v1/crd.go create mode 100755 pkg/tools/TestGenCommand__crd.out.yaml diff --git a/deploy/data/virtlet-ds.yaml b/deploy/data/virtlet-ds.yaml index b384c1f39..889bc9545 100644 --- a/deploy/data/virtlet-ds.yaml +++ b/deploy/data/virtlet-ds.yaml @@ -293,11 +293,13 @@ metadata: namespace: kube-system rules: - apiGroups: - - "" + - "" resources: - - configmaps + - configmaps + - nodes verbs: - - create + - create + - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole @@ -357,19 +359,20 @@ apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: virtlet-crd rules: - - apiGroups: - - "apiextensions.k8s.io" - resources: - - customresourcedefinitions - verbs: - - create - - apiGroups: - - "virtlet.k8s" - resources: - - virtletimagemappings - verbs: - - list - - get +- apiGroups: + - "apiextensions.k8s.io" + resources: + - customresourcedefinitions + verbs: + - create +- apiGroups: + - "virtlet.k8s" + resources: + - virtletimagemappings + - virtletconfigmappings + verbs: + - list + - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding diff --git a/pkg/api/virtlet.k8s/v1/crd.go b/pkg/api/virtlet.k8s/v1/crd.go new file mode 100644 index 000000000..7e0b692a4 --- /dev/null +++ b/pkg/api/virtlet.k8s/v1/crd.go @@ -0,0 +1,75 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// GetCRDDefinitions returns custom resource definitions for VirtletImageMapping kind in k8s. +func GetCRDDefinitions() []runtime.Object { + return []runtime.Object{ + &apiextensionsv1beta1.CustomResourceDefinition{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "apiextensions.k8s.io/v1beta1", + Kind: "CustomResourceDefinition", + }, + ObjectMeta: meta_v1.ObjectMeta{ + Labels: map[string]string{ + "virtlet.cloud": "", + }, + Name: "virtletimagemappings." + groupName, + }, + Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ + Group: groupName, + Version: version, + Scope: apiextensionsv1beta1.NamespaceScoped, + Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ + Plural: "virtletimagemappings", + Singular: "virtletimagemapping", + Kind: "VirtletImageMapping", + ShortNames: []string{"vim"}, + }, + }, + }, + &apiextensionsv1beta1.CustomResourceDefinition{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "apiextensions.k8s.io/v1beta1", + Kind: "CustomResourceDefinition", + }, + ObjectMeta: meta_v1.ObjectMeta{ + Labels: map[string]string{ + "virtlet.cloud": "", + }, + Name: "virtletconfigmappings." + groupName, + }, + Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ + Group: groupName, + Version: version, + Scope: apiextensionsv1beta1.NamespaceScoped, + Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ + Plural: "virtletconfigmappings", + Singular: "virtletconfigmapping", + Kind: "VirtletConfigMapping", + ShortNames: []string{"vcm"}, + }, + }, + }, + } +} diff --git a/pkg/api/virtlet.k8s/v1/register.go b/pkg/api/virtlet.k8s/v1/register.go index 0e6e3fc3a..c7d1652bd 100644 --- a/pkg/api/virtlet.k8s/v1/register.go +++ b/pkg/api/virtlet.k8s/v1/register.go @@ -17,14 +17,9 @@ limitations under the License. package v1 import ( - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - apierrors "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - - "github.com/Mirantis/virtlet/pkg/utils" ) const ( @@ -39,67 +34,11 @@ var ( AddToScheme = schemeBuilder.AddToScheme ) -// Resource takes an unqualified resource and returns a Group qualified GroupResource +// Resource takes an unqualified resource and returns a Group qualified GroupResource. func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } -// RegisterCustomResourceTypes registers custom resource definition for VirtletImageMapping kind in k8s -func RegisterCustomResourceTypes() error { - crds := []apiextensionsv1beta1.CustomResourceDefinition{ - { - ObjectMeta: meta_v1.ObjectMeta{ - Name: "virtletimagemappings." + groupName, - }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: groupName, - Version: version, - Scope: apiextensionsv1beta1.NamespaceScoped, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Plural: "virtletimagemappings", - Singular: "virtletimagemapping", - Kind: "VirtletImageMapping", - ShortNames: []string{"vim"}, - }, - }, - }, - { - ObjectMeta: meta_v1.ObjectMeta{ - Name: "virtletconfigmappings." + groupName, - }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: groupName, - Version: version, - Scope: apiextensionsv1beta1.NamespaceScoped, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Plural: "virtletconfigmappings", - Singular: "virtletconfigmapping", - Kind: "VirtletConfigMapping", - ShortNames: []string{"vcm"}, - }, - }, - }, - } - cfg, err := utils.GetK8sClientConfig("") - if err != nil || cfg.Host == "" { - return err - } - extensionsClientSet, err := apiextensionsclient.NewForConfig(cfg) - if err != nil { - panic(err) - } - - for _, crd := range crds { - _, err = extensionsClientSet.ApiextensionsV1beta1().CustomResourceDefinitions().Create(&crd) - if err == nil || apierrors.IsAlreadyExists(err) { - continue - } - return err - } - - return nil -} - func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &VirtletImageMapping{}, @@ -112,7 +51,5 @@ func addKnownTypes(scheme *runtime.Scheme) error { } func init() { - if err := schemeBuilder.AddToScheme(scheme); err != nil { - panic(err) - } + schemeBuilder.Register(addKnownTypes) } diff --git a/pkg/api/virtlet.k8s/v1/virtletconfig.go b/pkg/api/virtlet.k8s/v1/virtletconfig.go index 38f76d553..908337175 100644 --- a/pkg/api/virtlet.k8s/v1/virtletconfig.go +++ b/pkg/api/virtlet.k8s/v1/virtletconfig.go @@ -87,5 +87,5 @@ type VirtletConfigMapping struct { type VirtletConfigMappingList struct { meta_v1.TypeMeta `json:",inline"` meta_v1.ListMeta `json:"metadata"` - Items []VirtletConfigMapping `json:"mappings,omitempty"` + Items []VirtletConfigMapping `json:"items,omitempty"` } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index f4476aa0c..681b5fe82 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -89,9 +89,6 @@ func (v *VirtletManager) Run() error { var translator image.Translator if !*v.config.SkipImageTranslation { - if err = v1.RegisterCustomResourceTypes(); err != nil { - return fmt.Errorf("failed to register image translation CRD: %v", err) - } translator = imagetranslation.GetDefaultImageTranslator(*v.config.ImageTranslationConfigsDir, *v.config.EnableRegexpImageTranslation, v.clientCfg) } else { translator = imagetranslation.GetEmptyImageTranslator() diff --git a/pkg/tools/TestGenCommand__compat.out.yaml b/pkg/tools/TestGenCommand__compat.out.yaml index 58f1bfe0c..ecca73263 100755 --- a/pkg/tools/TestGenCommand__compat.out.yaml +++ b/pkg/tools/TestGenCommand__compat.out.yaml @@ -287,8 +287,10 @@ rules: - "" resources: - configmaps + - nodes verbs: - create + - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 @@ -368,6 +370,7 @@ rules: - virtlet.k8s resources: - virtletimagemappings + - virtletconfigmappings verbs: - list - get @@ -395,3 +398,51 @@ metadata: name: virtlet namespace: kube-system +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletimagemappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletImageMapping + plural: virtletimagemappings + shortNames: + - vim + singular: virtletimagemapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletconfigmappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletConfigMapping + plural: virtletconfigmappings + shortNames: + - vcm + singular: virtletconfigmapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + diff --git a/pkg/tools/TestGenCommand__compat_dev.out.yaml b/pkg/tools/TestGenCommand__compat_dev.out.yaml index eec905a88..19a781a01 100755 --- a/pkg/tools/TestGenCommand__compat_dev.out.yaml +++ b/pkg/tools/TestGenCommand__compat_dev.out.yaml @@ -298,8 +298,10 @@ rules: - "" resources: - configmaps + - nodes verbs: - create + - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 @@ -379,6 +381,7 @@ rules: - virtlet.k8s resources: - virtletimagemappings + - virtletconfigmappings verbs: - list - get @@ -406,3 +409,51 @@ metadata: name: virtlet namespace: kube-system +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletimagemappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletImageMapping + plural: virtletimagemappings + shortNames: + - vim + singular: virtletimagemapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletconfigmappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletConfigMapping + plural: virtletconfigmappings + shortNames: + - vcm + singular: virtletconfigmapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + diff --git a/pkg/tools/TestGenCommand__crd.out.yaml b/pkg/tools/TestGenCommand__crd.out.yaml new file mode 100755 index 000000000..fd4580cd1 --- /dev/null +++ b/pkg/tools/TestGenCommand__crd.out.yaml @@ -0,0 +1,48 @@ +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletimagemappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletImageMapping + plural: virtletimagemappings + shortNames: + - vim + singular: virtletimagemapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletconfigmappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletConfigMapping + plural: virtletconfigmappings + shortNames: + - vcm + singular: virtletconfigmapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + diff --git a/pkg/tools/TestGenCommand__dev.out.yaml b/pkg/tools/TestGenCommand__dev.out.yaml index 1ce77ea3e..2b1e17f62 100755 --- a/pkg/tools/TestGenCommand__dev.out.yaml +++ b/pkg/tools/TestGenCommand__dev.out.yaml @@ -302,8 +302,10 @@ rules: - "" resources: - configmaps + - nodes verbs: - create + - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 @@ -383,6 +385,7 @@ rules: - virtlet.k8s resources: - virtletimagemappings + - virtletconfigmappings verbs: - list - get @@ -410,3 +413,51 @@ metadata: name: virtlet namespace: kube-system +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletimagemappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletImageMapping + plural: virtletimagemappings + shortNames: + - vim + singular: virtletimagemapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletconfigmappings.virtlet.k8s +spec: + group: virtlet.k8s + names: + kind: VirtletConfigMapping + plural: virtletconfigmappings + shortNames: + - vcm + singular: virtletconfigmapping + scope: Namespaced + version: v1 +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + diff --git a/pkg/tools/TestGenCommand__plain.out.yaml b/pkg/tools/TestGenCommand__plain.out.yaml index b384c1f39..88405bb6a 100755 --- a/pkg/tools/TestGenCommand__plain.out.yaml +++ b/pkg/tools/TestGenCommand__plain.out.yaml @@ -2,24 +2,17 @@ apiVersion: extensions/v1beta1 kind: DaemonSet metadata: + creationTimestamp: null name: virtlet namespace: kube-system spec: template: metadata: - name: virtlet + creationTimestamp: null labels: runtime: virtlet + name: virtlet spec: - hostNetwork: true - dnsPolicy: ClusterFirstWithHostNet - # hostPID is true to (1) enable VMs to survive virtlet container restart - # (to be checked) and (2) to enable the use of nsenter in init container - hostPID: true - # bootstrap procedure needs to create a configmap in kube-system namespace - serviceAccountName: virtlet - - # only run Virtlet pods on the nodes with extraRuntime=virtlet label affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -29,35 +22,107 @@ spec: operator: In values: - virtlet - - initContainers: - # The init container copies virtlet's flexvolume driver - # to the default kubelet plugin dir and ensures that - # the directories needed by libvirt & virtlet exist on the host - - name: prepare-node + containers: + - command: + - /libvirt.sh image: mirantis/virtlet imagePullPolicy: IfNotPresent - command: - - /prepare-node.sh + name: libvirt + readinessProbe: + exec: + command: + - /bin/sh + - -c + - socat - UNIX:/var/run/libvirt/libvirt-sock-ro Date: Thu, 7 Jun 2018 21:47:17 +0300 Subject: [PATCH 07/17] Update build/cmd.sh to support mutinode and CRDs --- build/cmd.sh | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/build/cmd.sh b/build/cmd.sh index 2ece46aa8..36657203e 100755 --- a/build/cmd.sh +++ b/build/cmd.sh @@ -9,6 +9,7 @@ VIRTLET_IMAGE="${VIRTLET_IMAGE:-mirantis/virtlet}" VIRTLET_SKIP_RSYNC="${VIRTLET_SKIP_RSYNC:-}" VIRTLET_RSYNC_PORT="${VIRTLET_RSYNC_PORT:-18730}" VIRTLET_ON_MASTER="${VIRTLET_ON_MASTER:-}" +VIRTLET_MULTI_NODE="${VIRTLET_MULTI_NODE:-}" # XXX: try to extract the docker socket path from DOCKER_HOST if it's set to unix://... DOCKER_SOCKET_PATH="${DOCKER_SOCKET_PATH:-/var/run/docker.sock}" FORCE_UPDATE_IMAGE="${FORCE_UPDATE_IMAGE:-}" @@ -32,9 +33,15 @@ exclude=( ) rsync_pw_file="${project_dir}/_output/rsync.password" busybox_image=busybox:1.27.2 -virtlet_node=kube-node-1 +virtlet_nodes=() if [[ ${VIRTLET_ON_MASTER} ]]; then - virtlet_node=kube-master + virtlet_nodes+=(kube-master) +fi +if [[ !${VIRTLET_ON_MASTER} || ${VIRTLET_MULTI_NODE} ]]; then + virtlet_nodes+=(kube-node-1) +fi +if [[ ${VIRTLET_MULTI_NODE} ]]; then + virtlet_nodes+=(kube-node-2) fi bindata_modtime=1522279343 bindata_out="pkg/tools/bindata.go" @@ -169,6 +176,7 @@ function ensure_build_container { -e CIRCLE_PULL_REQUEST="${CIRCLE_PULL_REQUEST:-}" \ -e CIRCLE_BRANCH="${CIRCLE_PULL_REQUEST:-}" \ -e VIRTLET_ON_MASTER="${VIRTLET_ON_MASTER:-}" \ + -e VIRTLET_MULTI_NODE="${VIRTLET_MULTI_NODE:-}" \ -e GITHUB_TOKEN="${GITHUB_TOKEN:-}" \ ${docker_cert_args[@]+"${docker_cert_args[@]}"} \ --name virtlet-build \ @@ -244,6 +252,7 @@ function copy_back { } function copy_dind_internal { + local virtlet_node="${1}" if ! docker volume ls -q | grep -q "^kubeadm-dind-${virtlet_node}$"; then echo "No active or snapshotted kubeadm-dind-cluster" >&2 exit 1 @@ -260,12 +269,14 @@ function kvm_ok { # The check is done inside the virtlet node container because it # has proper /lib/modules from the docker host. Also, it'll have # to use the virtlet image later anyway. - if ! docker exec "${virtlet_node}" docker run --privileged --rm -v /lib/modules:/lib/modules "${VIRTLET_IMAGE}" kvm-ok; then + # Use kube-master node as all of the DIND nodes in the cluster are similar + if ! docker exec kube-master docker run --privileged --rm -v /lib/modules:/lib/modules "${VIRTLET_IMAGE}" kvm-ok; then return 1 fi } -function start_dind { +function prepare_node { + local virtlet_node="${1}" ensure_build_container if ! docker exec "${virtlet_node}" dpkg-query -W criproxy-nodeps >&/dev/null; then echo >&2 "Installing CRI proxy package the node container..." @@ -286,11 +297,14 @@ function start_dind { echo >&2 "Propagating Virtlet image to the node container..." vcmd "docker save '${virtlet_image}' | docker exec -i '${virtlet_node}' docker load" fi + kubectl label node --overwrite "${virtlet_node}" extraRuntime=virtlet +} + +function start_dind { local -a virtlet_config=(--from-literal=image_regexp_translation="${IMAGE_REGEXP_TRANSLATION}") if ! kvm_ok || [[ ${VIRTLET_DISABLE_KVM:-} ]]; then virtlet_config+=(--from-literal=disable_kvm=y) fi - kubectl label node --overwrite "${virtlet_node}" extraRuntime=virtlet kubectl create configmap -n kube-system virtlet-config "${virtlet_config[@]}" kubectl create configmap -n kube-system virtlet-image-translations --from-file "${project_dir}/deploy/images.yaml" start_virtlet @@ -562,9 +576,14 @@ case "${cmd}" in e2e "$@" ;; copy-dind-internal) - copy_dind_internal + for virtlet_node in "${virtlet_nodes[@]}"; do + copy_dind_internal "${virtlet_node}" + done ;; start-dind) + for virtlet_node in "${virtlet_nodes[@]}"; do + prepare_node "${virtlet_node}" + done start_dind ;; start-build-container) From 507eb9ad8a8bd3f763d3009e1ed45cfa8ade72bb Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Sun, 10 Jun 2018 00:57:03 +0300 Subject: [PATCH 08/17] Use separate spec & nodeSelector for configs --- pkg/api/virtlet.k8s/v1/virtletconfig.go | 23 +++-- .../virtlet.k8s/v1/zz_generated.deepcopy.go | 44 +++++++-- pkg/config/config.go | 23 ++--- pkg/config/config_test.go | 97 +++++++++++-------- 4 files changed, 118 insertions(+), 69 deletions(-) diff --git a/pkg/api/virtlet.k8s/v1/virtletconfig.go b/pkg/api/virtlet.k8s/v1/virtletconfig.go index 908337175..b6945b496 100644 --- a/pkg/api/virtlet.k8s/v1/virtletconfig.go +++ b/pkg/api/virtlet.k8s/v1/virtletconfig.go @@ -63,6 +63,21 @@ type VirtletConfig struct { LogLevel *int `json:"logLevel,omitempty"` } +// VirtletConfigMappingSpec is the contents of a VirtletConfigMapping. +type VirtletConfigMappingSpec struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + // NodeSelector specifies the labels that must be matched for this + // mapping to apply to the node. + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // Node name to match. + NodeName string `json:"nodeName,omitempty"` + // Priority specifies the priority of this setting. + Priority int + // VirtletConfig to apply. + Config *VirtletConfig `json:"config,omitempty"` +} + // +genclient // +genclient:noStatus // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -72,12 +87,8 @@ type VirtletConfig struct { type VirtletConfigMapping struct { meta_v1.TypeMeta `json:",inline"` meta_v1.ObjectMeta `json:"metadata"` - // Node name to match. - NodeName string `json:"nodeName,omitempty"` - // Node label to match. - Label string `json:"label,omitempty"` - // VirtletConfig to apply. - Config *VirtletConfig `json:"config,omitempty"` + + Spec VirtletConfigMappingSpec `json:"spec,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go b/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go index bbd9e2255..4a2f94775 100644 --- a/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go +++ b/pkg/api/virtlet.k8s/v1/zz_generated.deepcopy.go @@ -315,15 +315,7 @@ func (in *VirtletConfigMapping) DeepCopyInto(out *VirtletConfigMapping) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Config != nil { - in, out := &in.Config, &out.Config - if *in == nil { - *out = nil - } else { - *out = new(VirtletConfig) - (*in).DeepCopyInto(*out) - } - } + in.Spec.DeepCopyInto(&out.Spec) return } @@ -378,6 +370,40 @@ func (in *VirtletConfigMappingList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtletConfigMappingSpec) DeepCopyInto(out *VirtletConfigMappingSpec) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Config != nil { + in, out := &in.Config, &out.Config + if *in == nil { + *out = nil + } else { + *out = new(VirtletConfig) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtletConfigMappingSpec. +func (in *VirtletConfigMappingSpec) DeepCopy() *VirtletConfigMappingSpec { + if in == nil { + return nil + } + out := new(VirtletConfigMappingSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VirtletImageMapping) DeepCopyInto(out *VirtletImageMapping) { *out = *in diff --git a/pkg/config/config.go b/pkg/config/config.go index a7686c6d9..4db1db2d8 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -115,14 +115,15 @@ func DumpEnv(c *virtlet_v1.VirtletConfig) string { } func mappingMatches(cm virtlet_v1.VirtletConfigMapping, nodeName string, nodeLabels map[string]string) bool { - if cm.Config == nil { + if cm.Spec.Config == nil { return false } - if cm.NodeName != "" && cm.NodeName != nodeName { + if cm.Spec.NodeName != "" && cm.Spec.NodeName != nodeName { return false } - if cm.Label != "" { - if _, found := nodeLabels[cm.Label]; !found { + for label, value := range cm.Spec.NodeSelector { + actual, found := nodeLabels[label] + if !found || actual != value { return false } } @@ -186,21 +187,13 @@ func configForNode(mappings []virtlet_v1.VirtletConfigMapping, localConfig *virt } sort.Slice(sortedMappings, func(i, j int) bool { a, b := sortedMappings[i], sortedMappings[j] - if a.NodeName == b.NodeName { - // This also covers the case where both names are empty. - return a.Label < b.Label - } else { - // This will place unnamed items earlier in the list. - // The order of node names among the items doesn't - // really matter as just one such item can match - // a node, but let's keep it stable. - return a.NodeName < b.NodeName - } + // Iitems that go later in the list take precedence. + return a.Spec.Priority < b.Spec.Priority }) configs := []*virtlet_v1.VirtletConfig{cfg} for _, m := range sortedMappings { - configs = append(configs, m.Config) + configs = append(configs, m.Spec.Config) } if localConfig != nil { configs = append(configs, localConfig) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 3cf20dd10..3f71c3b03 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -168,43 +168,58 @@ func TestMergeConfigs(t *testing.T) { const ( fullConfig = ` -config: - fdServerSocketPath: /some/fd/server.sock - databasePath: /some/file.db - downloadProtocol: http - imageTranslationConfigsDir: /some/translation/dir - libvirtURI: qemu:///foobar - rawDevices: sd* - criSocketPath: /some/cri.sock - disableLogging: true - disableKVM: true - enableSriov: true - cniPluginDir: /some/cni/bin/dir - cniConfigDir: /some/cni/conf/dir - calicoSubnetSize: 22 - enableRegexpImageTranslation: false - logLevel: 3` - kubeNode1FullMapping = "nodeName: kube-node-1" + fullConfig - labelAFullMapping = "label: label-a" + fullConfig - anotherMapping1 = ` -nodeName: kube-node-1 -config: - enableSriov: false - disableKVM: true` + config: + fdServerSocketPath: /some/fd/server.sock + databasePath: /some/file.db + downloadProtocol: http + imageTranslationConfigsDir: /some/translation/dir + libvirtURI: qemu:///foobar + rawDevices: sd* + criSocketPath: /some/cri.sock + disableLogging: true + disableKVM: true + enableSriov: true + cniPluginDir: /some/cni/bin/dir + cniConfigDir: /some/cni/conf/dir + calicoSubnetSize: 22 + enableRegexpImageTranslation: false + logLevel: 3` + kubeNode1FullMapping = ` +spec: + nodeName: kube-node-1 + priority: 10` + fullConfig + labelAFullMapping = ` +spec: + nodeSelector: + label-a: "1"` + fullConfig + anotherMapping1 = ` +spec: + nodeName: kube-node-1 + priority: 10 + config: + enableSriov: false + disableKVM: true` anotherMapping2 = ` -label: label-b -config: +spec: + nodeSelector: + label-b: "1" + priority: 1 + config: rawDevices: vd* downloadProtocol: http` anotherMapping3 = ` -nodeName: kube-node-2 -config: - disableLogging: true` +spec: + nodeName: kube-node-2 + priority: 10 + config: + disableLogging: true` anotherMapping4 = ` -label: label-a -config: - enableSriov: true - rawDevices: sd*` +spec: + nodeSelector: + label-a: "1" + config: + enableSriov: true + rawDevices: sd*` sampleLocalConfig = ` disableKVM: false ` @@ -304,10 +319,12 @@ func TestLoadMappings(t *testing.T) { Name: "mapping-1", Namespace: "kube-system", }, - NodeName: "kube-node-1", - Config: &virtlet_v1.VirtletConfig{ - EnableSriov: pbool(true), - DisableKVM: pbool(true), + Spec: virtlet_v1.VirtletConfigMappingSpec{ + NodeName: "kube-node-1", + Config: &virtlet_v1.VirtletConfig{ + EnableSriov: pbool(true), + DisableKVM: pbool(true), + }, }, }, &virtlet_v1.VirtletConfigMapping{ @@ -315,9 +332,11 @@ func TestLoadMappings(t *testing.T) { Name: "mapping-2", Namespace: "kube-system", }, - Label: "label-a", - Config: &virtlet_v1.VirtletConfig{ - RawDevices: pstr("sd*"), + Spec: virtlet_v1.VirtletConfigMappingSpec{ + NodeSelector: map[string]string{"label-a": "1"}, + Config: &virtlet_v1.VirtletConfig{ + RawDevices: pstr("sd*"), + }, }, }) cfg, err := nc.LoadConfig(&virtlet_v1.VirtletConfig{ From cdaa99abe193b8be3af296ec059e3fbbccd8452b Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Mon, 11 Jun 2018 00:49:43 +0300 Subject: [PATCH 09/17] Implement CRD validation --- pkg/api/virtlet.k8s/v1/crd.go | 75 ------------ pkg/config/TestGetCRDDefinitions.out.yaml | 96 +++++++++++++++ pkg/config/config.go | 35 +++--- pkg/config/crd.go | 111 ++++++++++++++++++ pkg/config/crd_test.go | 27 +++++ pkg/config/fields.go | 73 ++++++++++-- pkg/tools/TestGenCommand__compat.out.yaml | 52 ++++++++ pkg/tools/TestGenCommand__compat_dev.out.yaml | 52 ++++++++ pkg/tools/TestGenCommand__crd.out.yaml | 52 ++++++++ pkg/tools/TestGenCommand__dev.out.yaml | 52 ++++++++ pkg/tools/TestGenCommand__plain.out.yaml | 52 ++++++++ pkg/tools/TestGenCommand__tag.out.yaml | 52 ++++++++ pkg/tools/gen.go | 4 +- 13 files changed, 626 insertions(+), 107 deletions(-) delete mode 100644 pkg/api/virtlet.k8s/v1/crd.go create mode 100755 pkg/config/TestGetCRDDefinitions.out.yaml create mode 100644 pkg/config/crd.go create mode 100644 pkg/config/crd_test.go diff --git a/pkg/api/virtlet.k8s/v1/crd.go b/pkg/api/virtlet.k8s/v1/crd.go deleted file mode 100644 index 7e0b692a4..000000000 --- a/pkg/api/virtlet.k8s/v1/crd.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2018 Mirantis - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// GetCRDDefinitions returns custom resource definitions for VirtletImageMapping kind in k8s. -func GetCRDDefinitions() []runtime.Object { - return []runtime.Object{ - &apiextensionsv1beta1.CustomResourceDefinition{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "apiextensions.k8s.io/v1beta1", - Kind: "CustomResourceDefinition", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Labels: map[string]string{ - "virtlet.cloud": "", - }, - Name: "virtletimagemappings." + groupName, - }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: groupName, - Version: version, - Scope: apiextensionsv1beta1.NamespaceScoped, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Plural: "virtletimagemappings", - Singular: "virtletimagemapping", - Kind: "VirtletImageMapping", - ShortNames: []string{"vim"}, - }, - }, - }, - &apiextensionsv1beta1.CustomResourceDefinition{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "apiextensions.k8s.io/v1beta1", - Kind: "CustomResourceDefinition", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Labels: map[string]string{ - "virtlet.cloud": "", - }, - Name: "virtletconfigmappings." + groupName, - }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: groupName, - Version: version, - Scope: apiextensionsv1beta1.NamespaceScoped, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Plural: "virtletconfigmappings", - Singular: "virtletconfigmapping", - Kind: "VirtletConfigMapping", - ShortNames: []string{"vcm"}, - }, - }, - }, - } -} diff --git a/pkg/config/TestGetCRDDefinitions.out.yaml b/pkg/config/TestGetCRDDefinitions.out.yaml new file mode 100755 index 000000000..6f29c5ef0 --- /dev/null +++ b/pkg/config/TestGetCRDDefinitions.out.yaml @@ -0,0 +1,96 @@ +- apiVersion: apiextensions.k8s.io/v1beta1 + kind: CustomResourceDefinition + metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletimagemappings.virtlet.k8s + spec: + group: virtlet.k8s + names: + kind: VirtletImageMapping + plural: virtletimagemappings + shortNames: + - vim + singular: virtletimagemapping + scope: Namespaced + version: v1 + status: + acceptedNames: + kind: "" + plural: "" + conditions: null +- apiVersion: apiextensions.k8s.io/v1beta1 + kind: CustomResourceDefinition + metadata: + creationTimestamp: null + labels: + virtlet.cloud: "" + name: virtletconfigmappings.virtlet.k8s + spec: + group: virtlet.k8s + names: + kind: VirtletConfigMapping + plural: virtletconfigmappings + shortNames: + - vcm + singular: virtletconfigmapping + scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer + version: v1 + status: + acceptedNames: + kind: "" + plural: "" + conditions: null diff --git a/pkg/config/config.go b/pkg/config/config.go index 4db1db2d8..4f48673cf 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -18,6 +18,7 @@ package config import ( "fmt" + "math" "sort" virtletclient "github.com/Mirantis/virtlet/pkg/client/clientset/versioned" @@ -73,25 +74,25 @@ const ( func configFieldSet(c *virtlet_v1.VirtletConfig) *fieldSet { var fs fieldSet - fs.addStringField("fd-server-socket-path", "", "Path to fd server socket", fdServerSocketPathEnv, defaultFDServerSocketPath, &c.FDServerSocketPath) - fs.addStringField("database-path", "", "Path to the virtlet database", databasePathEnv, defaultDatabasePath, &c.DatabasePath) - fs.addStringField("image-download-protocol", "", "Image download protocol. Can be https or http", imageDownloadProtocolEnv, defaultDownloadProtocol, &c.DownloadProtocol) - fs.addStringField("image-dir", "", "Image directory", imageDirEnv, defaultImageDir, &c.ImageDir) - fs.addStringField("image-translation-configs-dir", "", "Image name translation configs directory", imageTranslationsConfigDirEnv, defaultImageTranslationConfigsDir, &c.ImageTranslationConfigsDir) + fs.addStringField("fdServerSocketPath", "fd-server-socket-path", "", "Path to fd server socket", fdServerSocketPathEnv, defaultFDServerSocketPath, &c.FDServerSocketPath) + fs.addStringField("databasePath", "database-path", "", "Path to the virtlet database", databasePathEnv, defaultDatabasePath, &c.DatabasePath) + fs.addStringFieldWithPattern("downloadProtocol", "image-download-protocol", "", "Image download protocol. Can be https or http", imageDownloadProtocolEnv, defaultDownloadProtocol, "^https?$", &c.DownloadProtocol) + fs.addStringField("imageDir", "image-dir", "", "Image directory", imageDirEnv, defaultImageDir, &c.ImageDir) + fs.addStringField("imageTranslationConfigsDir", "image-translation-configs-dir", "", "Image name translation configs directory", imageTranslationsConfigDirEnv, defaultImageTranslationConfigsDir, &c.ImageTranslationConfigsDir) // SkipImageTranslation doesn't have corresponding flag or env var as it's only used by tests - fs.addBoolField("", "", "", "", false, &c.SkipImageTranslation) - fs.addStringField("libvirt-uri", "", "Libvirt connection URI", libvirtURIEnv, defaultLibvirtURI, &c.LibvirtURI) - fs.addStringField("raw-devices", "", "Comma separated list of raw device glob patterns which VMs can access (without '/dev/' prefix)", rawDevicesEnv, defaultRawDevices, &c.RawDevices) - fs.addStringField("listen", "", "The path to UNIX domain socket for CRI service to listen on", criSocketPathEnv, defaultCRISocketPath, &c.CRISocketPath) - fs.addBoolField("disable-logging", "", "Display logging and the streamer", disableLoggingEnv, false, &c.DisableLogging) - fs.addBoolField("disable-kvm", "", "Forcibly disable KVM support", disableKVMEnv, false, &c.DisableKVM) - fs.addBoolField("enable-sriov", "", "Enable SR-IOV support", enableSriovEnv, false, &c.EnableSriov) - fs.addStringField("cni-bin-dir", "", "Path to CNI plugin binaries", cniPluginDirEnv, defaultCNIPluginDir, &c.CNIPluginDir) - fs.addStringField("cni-conf-dir", "", "Path to the CNI configuration directory", cniConfigDirEnv, defaultCNIConfigDir, &c.CNIConfigDir) - fs.addIntField("calico-subnet-size", "", "Calico subnet size to use", calicoSubnetEnv, defaultCalicoSubnet, &c.CalicoSubnetSize) - fs.addBoolField("enable-regexp-image-translation", "", "Enable regexp image name translation", enableRegexpImageTranslationEnv, true, &c.EnableRegexpImageTranslation) + fs.addBoolField("skipImageTranslation", "", "", "", "", false, &c.SkipImageTranslation) + fs.addStringField("libvirtURI", "libvirt-uri", "", "Libvirt connection URI", libvirtURIEnv, defaultLibvirtURI, &c.LibvirtURI) + fs.addStringField("rawDevices", "raw-devices", "", "Comma separated list of raw device glob patterns which VMs can access (without '/dev/' prefix)", rawDevicesEnv, defaultRawDevices, &c.RawDevices) + fs.addStringField("criSocketPath", "listen", "", "The path to UNIX domain socket for CRI service to listen on", criSocketPathEnv, defaultCRISocketPath, &c.CRISocketPath) + fs.addBoolField("disableLogging", "disable-logging", "", "Display logging and the streamer", disableLoggingEnv, false, &c.DisableLogging) + fs.addBoolField("disableKVM", "disable-kvm", "", "Forcibly disable KVM support", disableKVMEnv, false, &c.DisableKVM) + fs.addBoolField("enableSriov", "enable-sriov", "", "Enable SR-IOV support", enableSriovEnv, false, &c.EnableSriov) + fs.addStringField("cniPluginDir", "cni-bin-dir", "", "Path to CNI plugin binaries", cniPluginDirEnv, defaultCNIPluginDir, &c.CNIPluginDir) + fs.addStringField("cniConfigDir", "cni-conf-dir", "", "Path to the CNI configuration directory", cniConfigDirEnv, defaultCNIConfigDir, &c.CNIConfigDir) + fs.addIntField("calicoSubnetSize", "calico-subnet-size", "", "Calico subnet size to use", calicoSubnetEnv, defaultCalicoSubnet, 0, 32, &c.CalicoSubnetSize) + fs.addBoolField("enableRegexpImageTranslation", "enable-regexp-image-translation", "", "Enable regexp image name translation", enableRegexpImageTranslationEnv, true, &c.EnableRegexpImageTranslation) // this field duplicates glog's --v, so no option for it - fs.addIntField("", "", "", logLevelEnv, 1, &c.LogLevel) + fs.addIntField("logLevel", "", "", "", logLevelEnv, 1, 0, math.MaxInt32, &c.LogLevel) return &fs } diff --git a/pkg/config/crd.go b/pkg/config/crd.go new file mode 100644 index 000000000..00b46b8ca --- /dev/null +++ b/pkg/config/crd.go @@ -0,0 +1,111 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" +) + +func configMappingProps() *apiext.JSONSchemaProps { + return &apiext.JSONSchemaProps{ + Properties: map[string]apiext.JSONSchemaProps{ + "spec": apiext.JSONSchemaProps{ + Properties: map[string]apiext.JSONSchemaProps{ + "nodeName": apiext.JSONSchemaProps{ + Type: "string", + }, + "nodeSelector": apiext.JSONSchemaProps{ + Type: "object", + // FIXME: https://github.com/kubernetes/kubernetes/issues/59485 + // AdditionalProperties: &apiext.JSONSchemaPropsOrBool{ + // Allows: true, + // Schema: &apiext.JSONSchemaProps{ + // Type: "string", + // }, + // }, + }, + "priority": apiext.JSONSchemaProps{ + Type: "integer", + }, + "config": apiext.JSONSchemaProps{ + Properties: configFieldSet(&virtlet_v1.VirtletConfig{}).schemaProps(), + }, + }, + }, + }, + } +} + +// GetCRDDefinitions returns custom resource definitions for VirtletImageMapping kind in k8s. +func GetCRDDefinitions() []runtime.Object { + gv := virtlet_v1.SchemeGroupVersion + return []runtime.Object{ + &apiext.CustomResourceDefinition{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "apiextensions.k8s.io/v1beta1", + Kind: "CustomResourceDefinition", + }, + ObjectMeta: meta_v1.ObjectMeta{ + Labels: map[string]string{ + "virtlet.cloud": "", + }, + Name: "virtletimagemappings." + gv.Group, + }, + Spec: apiext.CustomResourceDefinitionSpec{ + Group: gv.Group, + Version: gv.Version, + Scope: apiext.NamespaceScoped, + Names: apiext.CustomResourceDefinitionNames{ + Plural: "virtletimagemappings", + Singular: "virtletimagemapping", + Kind: "VirtletImageMapping", + ShortNames: []string{"vim"}, + }, + }, + }, + &apiext.CustomResourceDefinition{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "apiextensions.k8s.io/v1beta1", + Kind: "CustomResourceDefinition", + }, + ObjectMeta: meta_v1.ObjectMeta{ + Labels: map[string]string{ + "virtlet.cloud": "", + }, + Name: "virtletconfigmappings." + gv.Group, + }, + Spec: apiext.CustomResourceDefinitionSpec{ + Group: gv.Group, + Version: gv.Version, + Scope: apiext.NamespaceScoped, + Names: apiext.CustomResourceDefinitionNames{ + Plural: "virtletconfigmappings", + Singular: "virtletconfigmapping", + Kind: "VirtletConfigMapping", + ShortNames: []string{"vcm"}, + }, + Validation: &apiext.CustomResourceValidation{ + OpenAPIV3Schema: configMappingProps(), + }, + }, + }, + } +} diff --git a/pkg/config/crd_test.go b/pkg/config/crd_test.go new file mode 100644 index 000000000..fa5b9c460 --- /dev/null +++ b/pkg/config/crd_test.go @@ -0,0 +1,27 @@ +/* +Copyright 2018 Mirantis + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "testing" + + "github.com/Mirantis/virtlet/tests/gm" +) + +func TestGetCRDDefinitions(t *testing.T) { + gm.Verify(t, gm.NewYamlVerifier(GetCRDDefinitions())) +} diff --git a/pkg/config/fields.go b/pkg/config/fields.go index d18a5080e..4773e368f 100644 --- a/pkg/config/fields.go +++ b/pkg/config/fields.go @@ -25,9 +25,11 @@ import ( "github.com/golang/glog" "github.com/kballard/go-shellquote" flag "github.com/spf13/pflag" + apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" ) type configField interface { + fieldName() string flagName() string envName() string applyDefault() @@ -37,21 +39,25 @@ type configField interface { override(from configField) setFromEnvValue(value string) envValue() string + schemaProps() (string, apiext.JSONSchemaProps) } type fieldBase struct { - name string + field string + flag string shorthand string usage string env string } -func (f *fieldBase) flagName() string { return f.name } -func (f *fieldBase) envName() string { return f.env } +func (f *fieldBase) fieldName() string { return f.field } +func (f *fieldBase) flagName() string { return f.flag } +func (f *fieldBase) envName() string { return f.env } type stringField struct { fieldBase defValue string + pattern string value **string } @@ -67,7 +73,7 @@ func (sf *stringField) clear() { *sf.value = nil } func (sf *stringField) present() bool { return *sf.value != nil } func (sf *stringField) addFlag(f *flag.FlagSet) { - f.StringVarP(*sf.value, sf.name, sf.shorthand, sf.defValue, sf.usage) + f.StringVarP(*sf.value, sf.flag, sf.shorthand, sf.defValue, sf.usage) } func (sf *stringField) override(from configField) { @@ -89,6 +95,13 @@ func (sf *stringField) envValue() string { return **sf.value } +func (sf *stringField) schemaProps() (string, apiext.JSONSchemaProps) { + return sf.field, apiext.JSONSchemaProps{ + Type: "string", + Pattern: sf.pattern, + } +} + type boolField struct { fieldBase defValue bool @@ -107,7 +120,7 @@ func (bf *boolField) clear() { *bf.value = nil } func (bf *boolField) present() bool { return *bf.value != nil } func (bf *boolField) addFlag(f *flag.FlagSet) { - f.BoolVarP(*bf.value, bf.name, bf.shorthand, bf.defValue, bf.usage) + f.BoolVarP(*bf.value, bf.flag, bf.shorthand, bf.defValue, bf.usage) } func (bf *boolField) override(from configField) { @@ -130,9 +143,17 @@ func (bf *boolField) envValue() string { return "1" } +func (bf *boolField) schemaProps() (string, apiext.JSONSchemaProps) { + return bf.field, apiext.JSONSchemaProps{ + Type: "boolean", + } +} + type intField struct { fieldBase defValue int + min int + max int value **int } @@ -148,7 +169,7 @@ func (intf *intField) clear() { *intf.value = nil } func (intf *intField) present() bool { return *intf.value != nil } func (intf *intField) addFlag(f *flag.FlagSet) { - f.IntVarP(*intf.value, intf.name, intf.shorthand, intf.defValue, intf.usage) + f.IntVarP(*intf.value, intf.flag, intf.shorthand, intf.defValue, intf.usage) } func (intf *intField) override(from configField) { @@ -161,7 +182,7 @@ func (intf *intField) override(from configField) { func (intf *intField) setFromEnvValue(value string) { if v, err := strconv.Atoi(value); err != nil { - glog.Warningf("bad value for int field %s: %q", intf.name, value) + glog.Warningf("bad value for int field %s: %q", intf.field, value) } else { *intf.value = &v } @@ -174,32 +195,49 @@ func (intf *intField) envValue() string { return strconv.Itoa(**intf.value) } +func (intf *intField) schemaProps() (string, apiext.JSONSchemaProps) { + min := float64(intf.min) + max := float64(intf.max) + return intf.field, apiext.JSONSchemaProps{ + Type: "integer", + Minimum: &min, + Maximum: &max, + } +} + type envLookup func(name string) (string, bool) type fieldSet struct { fields []configField } -func (fs *fieldSet) addStringField(name, shorthand, usage, env, defValue string, value **string) { +func (fs *fieldSet) addStringFieldWithPattern(field, flag, shorthand, usage, env, defValue, pattern string, value **string) { fs.addField(&stringField{ - fieldBase{name, shorthand, usage, env}, + fieldBase{field, flag, shorthand, usage, env}, defValue, + pattern, value, }) } -func (fs *fieldSet) addBoolField(name, shorthand, usage, env string, defValue bool, value **bool) { +func (fs *fieldSet) addStringField(field, flag, shorthand, usage, env, defValue string, value **string) { + fs.addStringFieldWithPattern(field, flag, shorthand, usage, env, defValue, "", value) +} + +func (fs *fieldSet) addBoolField(field, flag, shorthand, usage, env string, defValue bool, value **bool) { fs.addField(&boolField{ - fieldBase{name, shorthand, usage, env}, + fieldBase{field, flag, shorthand, usage, env}, defValue, value, }) } -func (fs *fieldSet) addIntField(name, shorthand, usage, env string, defValue int, value **int) { +func (fs *fieldSet) addIntField(field, flag, shorthand, usage, env string, defValue, min, max int, value **int) { fs.addField(&intField{ - fieldBase{name, shorthand, usage, env}, + fieldBase{field, flag, shorthand, usage, env}, defValue, + min, + max, value, }) } @@ -266,3 +304,12 @@ func (fs *fieldSet) dumpEnv() string { } return buf.String() } + +func (fs *fieldSet) schemaProps() map[string]apiext.JSONSchemaProps { + r := make(map[string]apiext.JSONSchemaProps) + for _, f := range fs.fields { + field, props := f.schemaProps() + r[field] = props + } + return r +} diff --git a/pkg/tools/TestGenCommand__compat.out.yaml b/pkg/tools/TestGenCommand__compat.out.yaml index ecca73263..895bf7794 100755 --- a/pkg/tools/TestGenCommand__compat.out.yaml +++ b/pkg/tools/TestGenCommand__compat.out.yaml @@ -439,6 +439,58 @@ spec: - vcm singular: virtletconfigmapping scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer version: v1 status: acceptedNames: diff --git a/pkg/tools/TestGenCommand__compat_dev.out.yaml b/pkg/tools/TestGenCommand__compat_dev.out.yaml index 19a781a01..07e19b8e9 100755 --- a/pkg/tools/TestGenCommand__compat_dev.out.yaml +++ b/pkg/tools/TestGenCommand__compat_dev.out.yaml @@ -450,6 +450,58 @@ spec: - vcm singular: virtletconfigmapping scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer version: v1 status: acceptedNames: diff --git a/pkg/tools/TestGenCommand__crd.out.yaml b/pkg/tools/TestGenCommand__crd.out.yaml index fd4580cd1..5ef8199d1 100755 --- a/pkg/tools/TestGenCommand__crd.out.yaml +++ b/pkg/tools/TestGenCommand__crd.out.yaml @@ -39,6 +39,58 @@ spec: - vcm singular: virtletconfigmapping scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer version: v1 status: acceptedNames: diff --git a/pkg/tools/TestGenCommand__dev.out.yaml b/pkg/tools/TestGenCommand__dev.out.yaml index 2b1e17f62..1478a1a04 100755 --- a/pkg/tools/TestGenCommand__dev.out.yaml +++ b/pkg/tools/TestGenCommand__dev.out.yaml @@ -454,6 +454,58 @@ spec: - vcm singular: virtletconfigmapping scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer version: v1 status: acceptedNames: diff --git a/pkg/tools/TestGenCommand__plain.out.yaml b/pkg/tools/TestGenCommand__plain.out.yaml index 88405bb6a..440e0c69d 100755 --- a/pkg/tools/TestGenCommand__plain.out.yaml +++ b/pkg/tools/TestGenCommand__plain.out.yaml @@ -443,6 +443,58 @@ spec: - vcm singular: virtletconfigmapping scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer version: v1 status: acceptedNames: diff --git a/pkg/tools/TestGenCommand__tag.out.yaml b/pkg/tools/TestGenCommand__tag.out.yaml index b87faf8af..a354bcaa1 100755 --- a/pkg/tools/TestGenCommand__tag.out.yaml +++ b/pkg/tools/TestGenCommand__tag.out.yaml @@ -443,6 +443,58 @@ spec: - vcm singular: virtletconfigmapping scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + properties: + config: + properties: + calicoSubnetSize: + maximum: 32 + minimum: 0 + type: integer + cniConfigDir: + type: string + cniPluginDir: + type: string + criSocketPath: + type: string + databasePath: + type: string + disableKVM: + type: boolean + disableLogging: + type: boolean + downloadProtocol: + pattern: ^https?$ + type: string + enableRegexpImageTranslation: + type: boolean + enableSriov: + type: boolean + fdServerSocketPath: + type: string + imageDir: + type: string + imageTranslationConfigsDir: + type: string + libvirtURI: + type: string + logLevel: + maximum: 2147483647 + minimum: 0 + type: integer + rawDevices: + type: string + skipImageTranslation: + type: boolean + nodeName: + type: string + nodeSelector: + type: object + priority: + type: integer version: v1 status: acceptedNames: diff --git a/pkg/tools/gen.go b/pkg/tools/gen.go index 2c8170836..574e9db73 100644 --- a/pkg/tools/gen.go +++ b/pkg/tools/gen.go @@ -25,7 +25,7 @@ import ( ext "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/runtime" - virtlet_v1 "github.com/Mirantis/virtlet/pkg/api/virtlet.k8s/v1" + "github.com/Mirantis/virtlet/pkg/config" "github.com/Mirantis/virtlet/pkg/version" ) @@ -95,7 +95,7 @@ func (g *genCommand) getYaml() ([]byte, error) { } } - objs = append(objs, virtlet_v1.GetCRDDefinitions()...) + objs = append(objs, config.GetCRDDefinitions()...) return ToYaml(objs) } From 9c73cc4e5b2af0452cfe148391d24c5a2fdd7a2f Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Mon, 11 Jun 2018 00:49:57 +0300 Subject: [PATCH 10/17] Fix Virtlet log level handling --- cmd/virtlet/virtlet.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmd/virtlet/virtlet.go b/cmd/virtlet/virtlet.go index 0833a3999..41c070ee5 100644 --- a/cmd/virtlet/virtlet.go +++ b/cmd/virtlet/virtlet.go @@ -17,6 +17,8 @@ limitations under the License. package main import ( + goflag "flag" + "fmt" "math/rand" "os" "os/exec" @@ -112,6 +114,13 @@ func printVersion() { } } +func setLogLevel(config *v1.VirtletConfig) { + goflag.CommandLine.Parse([]string{ + fmt.Sprintf("-v=%d", config.LogLevel), + "-logtostderr=true", + }) +} + func main() { utils.HandleNsFixReexec() clientCfg := utils.BindFlags(flag.CommandLine) @@ -121,6 +130,7 @@ func main() { localConfig := cb.GetConfig() rand.Seed(time.Now().UnixNano()) + setLogLevel(configWithDefaults(localConfig)) switch { case os.Getenv(wantTapManagerEnv) != "": localConfig = configWithDefaults(localConfig) From 3022a2aeecb1975ff61f314a555bbe31dc88ed5a Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:24:02 +0300 Subject: [PATCH 11/17] Add virtletctl gendoc --config --- cmd/virtletctl/virtletctl.go | 2 +- pkg/config/TestGenerateDoc.out.txt | 18 ++++++ pkg/config/config.go | 11 +++- pkg/config/config_test.go | 4 ++ pkg/config/fields.go | 80 +++++++++++++++++++++------ pkg/tools/TestGenDocForConfig.out.txt | 18 ++++++ pkg/tools/gendoc.go | 33 ++++++++--- pkg/tools/gendoc_test.go | 14 ++++- 8 files changed, 151 insertions(+), 29 deletions(-) create mode 100755 pkg/config/TestGenerateDoc.out.txt create mode 100755 pkg/tools/TestGenDocForConfig.out.txt diff --git a/cmd/virtletctl/virtletctl.go b/cmd/virtletctl/virtletctl.go index 8857653d2..639646f2a 100644 --- a/cmd/virtletctl/virtletctl.go +++ b/cmd/virtletctl/virtletctl.go @@ -48,7 +48,7 @@ func newRootCmd() *cobra.Command { cmd.AddCommand(tools.NewSSHCmd(client, os.Stdout, "")) cmd.AddCommand(tools.NewVNCCmd(client, os.Stdout, true)) cmd.AddCommand(tools.NewInstallCmd(cmd, "", "")) - cmd.AddCommand(tools.NewGenDocCmd(cmd)) + cmd.AddCommand(tools.NewGenDocCmd(cmd, os.Stdout)) cmd.AddCommand(tools.NewGenCmd(os.Stdout)) cmd.AddCommand(tools.NewVersionCommand(client, os.Stdout, nil)) diff --git a/pkg/config/TestGenerateDoc.out.txt b/pkg/config/TestGenerateDoc.out.txt new file mode 100755 index 000000000..dbdec7dd0 --- /dev/null +++ b/pkg/config/TestGenerateDoc.out.txt @@ -0,0 +1,18 @@ +| Description | Config field | Default value | Type | Command line flag / Env | +| --- | --- | --- | --- | --- | +| Path to fd server socket | `fdServerSocketPath` | `/var/lib/virtlet/tapfdserver.sock` | string | `--fd-server-socket-path` / `VIRTLET_FD_SERVER_SOCKET_PATH` | +| Path to the virtlet database | `databasePath` | `/var/lib/virtlet/virtlet.db` | string | `--database-path` / `VIRTLET_DATABASE_PATH` | +| Image download protocol. Can be https or http | `downloadProtocol` | `https` | string | `--image-download-protocol` / `VIRTLET_DOWNLOAD_PROTOCOL` | +| Image directory | `imageDir` | `/var/lib/virtlet/images` | string | `--image-dir` / `VIRTLET_IMAGE_DIR` | +| Image name translation configs directory | `imageTranslationConfigsDir` | `/etc/virtlet/images` | string | `--image-translation-configs-dir` / `VIRTLET_IMAGE_TRANSLATIONS_DIR` | +| Libvirt connection URI | `libvirtURI` | `qemu:///system` | string | `--libvirt-uri` / `VIRTLET_LIBVIRT_URI` | +| Comma separated list of raw device glob patterns which VMs can access (without '/dev/' prefix) | `rawDevices` | `loop*` | string | `--raw-devices` / `VIRTLET_RAW_DEVICES` | +| The path to UNIX domain socket for CRI service to listen on | `criSocketPath` | `/run/virtlet.sock` | string | `--listen` / `VIRTLET_CRI_SOCKET_PATH` | +| Display logging and the streamer | `disableLogging` | `false` | boolean | `--disable-logging` / `VIRTLET_DISABLE_LOGGING` | +| Forcibly disable KVM support | `disableKVM` | `false` | boolean | `--disable-kvm` / `VIRTLET_DISABLE_KVM` | +| Enable SR-IOV support | `enableSriov` | `false` | boolean | `--enable-sriov` / `VIRTLET_SRIOV_SUPPORT` | +| Path to CNI plugin binaries | `cniPluginDir` | `/opt/cni/bin` | string | `--cni-bin-dir` / `VIRTLET_CNI_PLUGIN_DIR` | +| Path to the CNI configuration directory | `cniConfigDir` | `/etc/cni/net.d` | string | `--cni-conf-dir` / `VIRTLET_CNI_CONFIG_DIR` | +| Calico subnet size to use | `calicoSubnetSize` | `24` | integer | `--calico-subnet-size` / `VIRTLET_CALICO_SUBNET` | +| Enable regexp image name translation | `enableRegexpImageTranslation` | `true` | boolean | `--enable-regexp-image-translation` / `IMAGE_REGEXP_TRANSLATION` | +| Log level to use | `logLevel` | `1` | integer | `--v` / `VIRTLET_LOGLEVEL` | diff --git a/pkg/config/config.go b/pkg/config/config.go index 4f48673cf..662c2751a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -91,8 +91,9 @@ func configFieldSet(c *virtlet_v1.VirtletConfig) *fieldSet { fs.addStringField("cniConfigDir", "cni-conf-dir", "", "Path to the CNI configuration directory", cniConfigDirEnv, defaultCNIConfigDir, &c.CNIConfigDir) fs.addIntField("calicoSubnetSize", "calico-subnet-size", "", "Calico subnet size to use", calicoSubnetEnv, defaultCalicoSubnet, 0, 32, &c.CalicoSubnetSize) fs.addBoolField("enableRegexpImageTranslation", "enable-regexp-image-translation", "", "Enable regexp image name translation", enableRegexpImageTranslationEnv, true, &c.EnableRegexpImageTranslation) - // this field duplicates glog's --v, so no option for it - fs.addIntField("logLevel", "", "", "", logLevelEnv, 1, 0, math.MaxInt32, &c.LogLevel) + // this field duplicates glog's --v, so no option for it, which is signified + // by "+" here (it's only for doc) + fs.addIntField("logLevel", "+v", "", "Log level to use", logLevelEnv, 1, 0, math.MaxInt32, &c.LogLevel) return &fs } @@ -115,6 +116,12 @@ func DumpEnv(c *virtlet_v1.VirtletConfig) string { return configFieldSet(c).dumpEnv() } +// GenerateDoc generates a markdown document with a table describing +// all the configuration settings. +func GenerateDoc() string { + return configFieldSet(&virtlet_v1.VirtletConfig{}).generateDoc() +} + func mappingMatches(cm virtlet_v1.VirtletConfigMapping, nodeName string, nodeLabels map[string]string) bool { if cm.Spec.Config == nil { return false diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 3f71c3b03..208062030 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -347,3 +347,7 @@ func TestLoadMappings(t *testing.T) { } gm.Verify(t, gm.NewYamlVerifier(cfg)) } + +func TestGenerateDoc(t *testing.T) { + gm.Verify(t, GenerateDoc()) +} diff --git a/pkg/config/fields.go b/pkg/config/fields.go index 4773e368f..e9ac52fd8 100644 --- a/pkg/config/fields.go +++ b/pkg/config/fields.go @@ -21,6 +21,7 @@ import ( "fmt" "os" "strconv" + "strings" "github.com/golang/glog" "github.com/kballard/go-shellquote" @@ -29,9 +30,11 @@ import ( ) type configField interface { + typeName() string fieldName() string flagName() string envName() string + defaultStr() string applyDefault() clear() present() bool @@ -40,19 +43,21 @@ type configField interface { setFromEnvValue(value string) envValue() string schemaProps() (string, apiext.JSONSchemaProps) + description() string } type fieldBase struct { field string flag string shorthand string - usage string + desc string env string } -func (f *fieldBase) fieldName() string { return f.field } -func (f *fieldBase) flagName() string { return f.flag } -func (f *fieldBase) envName() string { return f.env } +func (f *fieldBase) fieldName() string { return f.field } +func (f *fieldBase) flagName() string { return f.flag } +func (f *fieldBase) envName() string { return f.env } +func (f *fieldBase) description() string { return f.desc } type stringField struct { fieldBase @@ -63,6 +68,8 @@ type stringField struct { var _ configField = &stringField{} +func (sf *stringField) typeName() string { return "string" } +func (sf *stringField) defaultStr() string { return sf.defValue } func (sf *stringField) applyDefault() { if *sf.value == nil { *sf.value = &sf.defValue @@ -73,7 +80,7 @@ func (sf *stringField) clear() { *sf.value = nil } func (sf *stringField) present() bool { return *sf.value != nil } func (sf *stringField) addFlag(f *flag.FlagSet) { - f.StringVarP(*sf.value, sf.flag, sf.shorthand, sf.defValue, sf.usage) + f.StringVarP(*sf.value, sf.flag, sf.shorthand, sf.defValue, sf.desc) } func (sf *stringField) override(from configField) { @@ -110,6 +117,8 @@ type boolField struct { var _ configField = &boolField{} +func (bf *boolField) typeName() string { return "boolean" } +func (bf *boolField) defaultStr() string { return strconv.FormatBool(bf.defValue) } func (bf *boolField) applyDefault() { if *bf.value == nil { *bf.value = &bf.defValue @@ -120,7 +129,7 @@ func (bf *boolField) clear() { *bf.value = nil } func (bf *boolField) present() bool { return *bf.value != nil } func (bf *boolField) addFlag(f *flag.FlagSet) { - f.BoolVarP(*bf.value, bf.flag, bf.shorthand, bf.defValue, bf.usage) + f.BoolVarP(*bf.value, bf.flag, bf.shorthand, bf.defValue, bf.desc) } func (bf *boolField) override(from configField) { @@ -159,6 +168,8 @@ type intField struct { var _ configField = &intField{} +func (intf *intField) typeName() string { return "integer" } +func (intf *intField) defaultStr() string { return strconv.Itoa(intf.defValue) } func (intf *intField) applyDefault() { if *intf.value == nil { *intf.value = &intf.defValue @@ -169,7 +180,7 @@ func (intf *intField) clear() { *intf.value = nil } func (intf *intField) present() bool { return *intf.value != nil } func (intf *intField) addFlag(f *flag.FlagSet) { - f.IntVarP(*intf.value, intf.flag, intf.shorthand, intf.defValue, intf.usage) + f.IntVarP(*intf.value, intf.flag, intf.shorthand, intf.defValue, intf.desc) } func (intf *intField) override(from configField) { @@ -208,33 +219,35 @@ func (intf *intField) schemaProps() (string, apiext.JSONSchemaProps) { type envLookup func(name string) (string, bool) type fieldSet struct { - fields []configField + fields []configField + docTitle string + desc string } -func (fs *fieldSet) addStringFieldWithPattern(field, flag, shorthand, usage, env, defValue, pattern string, value **string) { +func (fs *fieldSet) addStringFieldWithPattern(field, flag, shorthand, desc, env, defValue, pattern string, value **string) { fs.addField(&stringField{ - fieldBase{field, flag, shorthand, usage, env}, + fieldBase{field, flag, shorthand, desc, env}, defValue, pattern, value, }) } -func (fs *fieldSet) addStringField(field, flag, shorthand, usage, env, defValue string, value **string) { - fs.addStringFieldWithPattern(field, flag, shorthand, usage, env, defValue, "", value) +func (fs *fieldSet) addStringField(field, flag, shorthand, desc, env, defValue string, value **string) { + fs.addStringFieldWithPattern(field, flag, shorthand, desc, env, defValue, "", value) } -func (fs *fieldSet) addBoolField(field, flag, shorthand, usage, env string, defValue bool, value **bool) { +func (fs *fieldSet) addBoolField(field, flag, shorthand, desc, env string, defValue bool, value **bool) { fs.addField(&boolField{ - fieldBase{field, flag, shorthand, usage, env}, + fieldBase{field, flag, shorthand, desc, env}, defValue, value, }) } -func (fs *fieldSet) addIntField(field, flag, shorthand, usage, env string, defValue, min, max int, value **int) { +func (fs *fieldSet) addIntField(field, flag, shorthand, desc, env string, defValue, min, max int, value **int) { fs.addField(&intField{ - fieldBase{field, flag, shorthand, usage, env}, + fieldBase{field, flag, shorthand, desc, env}, defValue, min, max, @@ -254,7 +267,7 @@ func (fs *fieldSet) applyDefaults() { func (fs *fieldSet) addFlags(flagSet *flag.FlagSet) { for _, f := range fs.fields { - if f.flagName() != "" { + if f.flagName() != "" && !strings.Contains("+", f.flagName()) { f.addFlag(flagSet) } } @@ -313,3 +326,36 @@ func (fs *fieldSet) schemaProps() map[string]apiext.JSONSchemaProps { } return r } + +func (fs *fieldSet) generateDoc() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, + "| Description | Config field | Default value | Type | Command line flag / Env |\n"+ + "| --- | --- | --- | --- | --- |\n") + esc := func(s string) string { return strings.Replace(s, "|", "\\|", -1) } + code := func(s string) string { + if s == "" { + return "" + } + return fmt.Sprintf("`%s`", esc(s)) + } + for _, f := range fs.fields { + if f.description() == "" { + continue + } + var flagEnv []string + if f.flagName() != "" { + flagEnv = append(flagEnv, code("--"+strings.Replace(f.flagName(), "+", "", -1))) + } + if f.envName() != "" { + flagEnv = append(flagEnv, code(f.envName())) + } + fmt.Fprintf(&buf, "| %s | %s | %s | %s | %s |\n", + esc(f.description()), + code(f.fieldName()), + code(f.defaultStr()), + f.typeName(), + strings.Join(flagEnv, " / ")) + } + return buf.String() +} diff --git a/pkg/tools/TestGenDocForConfig.out.txt b/pkg/tools/TestGenDocForConfig.out.txt new file mode 100755 index 000000000..dbdec7dd0 --- /dev/null +++ b/pkg/tools/TestGenDocForConfig.out.txt @@ -0,0 +1,18 @@ +| Description | Config field | Default value | Type | Command line flag / Env | +| --- | --- | --- | --- | --- | +| Path to fd server socket | `fdServerSocketPath` | `/var/lib/virtlet/tapfdserver.sock` | string | `--fd-server-socket-path` / `VIRTLET_FD_SERVER_SOCKET_PATH` | +| Path to the virtlet database | `databasePath` | `/var/lib/virtlet/virtlet.db` | string | `--database-path` / `VIRTLET_DATABASE_PATH` | +| Image download protocol. Can be https or http | `downloadProtocol` | `https` | string | `--image-download-protocol` / `VIRTLET_DOWNLOAD_PROTOCOL` | +| Image directory | `imageDir` | `/var/lib/virtlet/images` | string | `--image-dir` / `VIRTLET_IMAGE_DIR` | +| Image name translation configs directory | `imageTranslationConfigsDir` | `/etc/virtlet/images` | string | `--image-translation-configs-dir` / `VIRTLET_IMAGE_TRANSLATIONS_DIR` | +| Libvirt connection URI | `libvirtURI` | `qemu:///system` | string | `--libvirt-uri` / `VIRTLET_LIBVIRT_URI` | +| Comma separated list of raw device glob patterns which VMs can access (without '/dev/' prefix) | `rawDevices` | `loop*` | string | `--raw-devices` / `VIRTLET_RAW_DEVICES` | +| The path to UNIX domain socket for CRI service to listen on | `criSocketPath` | `/run/virtlet.sock` | string | `--listen` / `VIRTLET_CRI_SOCKET_PATH` | +| Display logging and the streamer | `disableLogging` | `false` | boolean | `--disable-logging` / `VIRTLET_DISABLE_LOGGING` | +| Forcibly disable KVM support | `disableKVM` | `false` | boolean | `--disable-kvm` / `VIRTLET_DISABLE_KVM` | +| Enable SR-IOV support | `enableSriov` | `false` | boolean | `--enable-sriov` / `VIRTLET_SRIOV_SUPPORT` | +| Path to CNI plugin binaries | `cniPluginDir` | `/opt/cni/bin` | string | `--cni-bin-dir` / `VIRTLET_CNI_PLUGIN_DIR` | +| Path to the CNI configuration directory | `cniConfigDir` | `/etc/cni/net.d` | string | `--cni-conf-dir` / `VIRTLET_CNI_CONFIG_DIR` | +| Calico subnet size to use | `calicoSubnetSize` | `24` | integer | `--calico-subnet-size` / `VIRTLET_CALICO_SUBNET` | +| Enable regexp image name translation | `enableRegexpImageTranslation` | `true` | boolean | `--enable-regexp-image-translation` / `IMAGE_REGEXP_TRANSLATION` | +| Log level to use | `logLevel` | `1` | integer | `--v` / `VIRTLET_LOGLEVEL` | diff --git a/pkg/tools/gendoc.go b/pkg/tools/gendoc.go index 181daaaed..459932b9b 100644 --- a/pkg/tools/gendoc.go +++ b/pkg/tools/gendoc.go @@ -18,37 +18,54 @@ package tools import ( "errors" + "fmt" + "io" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" + + "github.com/Mirantis/virtlet/pkg/config" ) // genDocCommand is used to generate markdown documentation for // virtletctl commands. type genDocCommand struct { rootCmd *cobra.Command + out io.Writer outDir string + config bool } // NewGenDocCmd returns a cobra.Command that generates markdown // documentation for virtletctl commands. -func NewGenDocCmd(rootCmd *cobra.Command) *cobra.Command { - gd := &genDocCommand{rootCmd: rootCmd} - return &cobra.Command{ +func NewGenDocCmd(rootCmd *cobra.Command, out io.Writer) *cobra.Command { + gd := &genDocCommand{rootCmd: rootCmd, out: out} + cmd := &cobra.Command{ Use: "gendoc output_dir", Short: "Generate Markdown documentation for the commands", - Long: "This command produces documentation for the whole command tree.", + Long: "This command produces documentation for the whole command tree, or the Virtlet configuration data.", RunE: func(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return errors.New("Must specify the output directory") + switch { + case !gd.config && len(args) != 1: + return errors.New("Must specify the output directory or --config") + case !gd.config: + gd.outDir = args[0] + case len(args) != 0: + return errors.New("Can't specify both the output directory and --config") } - gd.outDir = args[0] return gd.Run() }, } + cmd.Flags().BoolVar(&gd.config, "config", false, "Produce documentation for Virtlet config") + return cmd } // Run executes the command. func (gd *genDocCommand) Run() error { - return doc.GenMarkdownTree(gd.rootCmd, gd.outDir) + if gd.config { + fmt.Fprint(gd.out, config.GenerateDoc()) + } else { + return doc.GenMarkdownTree(gd.rootCmd, gd.outDir) + } + return nil } diff --git a/pkg/tools/gendoc_test.go b/pkg/tools/gendoc_test.go index 0899f0ac2..9cbfc8495 100644 --- a/pkg/tools/gendoc_test.go +++ b/pkg/tools/gendoc_test.go @@ -34,7 +34,7 @@ func TestGenDocCommand(t *testing.T) { } defer os.RemoveAll(tmpDir) - cmd := NewGenDocCmd(fakeCobraCommand()) + cmd := NewGenDocCmd(fakeCobraCommand(), nil) cmd.SilenceUsage = true cmd.SilenceErrors = true cmd.SetArgs([]string{tmpDir}) @@ -61,3 +61,15 @@ func TestGenDocCommand(t *testing.T) { } gm.Verify(t, buf.Bytes()) } + +func TestGenDocForConfig(t *testing.T) { + var buf bytes.Buffer + cmd := NewGenDocCmd(nil, &buf) + cmd.SilenceUsage = true + cmd.SilenceErrors = true + cmd.SetArgs([]string{"--config"}) + if err := cmd.Execute(); err != nil { + t.Errorf("Error running gendoc command: %v", err) + } + gm.Verify(t, buf.Bytes()) +} From 79561a59dccb64ac23b3805c1b6e8591fd7b05f4 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:25:07 +0300 Subject: [PATCH 12/17] Add build/cmd.sh update-docs --- build/cmd.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/build/cmd.sh b/build/cmd.sh index 36657203e..63196a336 100755 --- a/build/cmd.sh +++ b/build/cmd.sh @@ -488,6 +488,20 @@ function update_bindata_internal { go-bindata -modtime "${bindata_modtime}" -o "${bindata_out}" -pkg "${bindata_pkg}" "${bindata_dir}" } +function update_docs_internal { + if [[ ! -f _output/virtletctl ]]; then + echo >&2 "Please run build/cmd.sh build first" + fi + _output/virtletctl gendoc docs/virtletctl + tempfile="$(tempfile)" + _output/virtletctl gendoc --config >"${tempfile}" + sed -i "//,//{ +//!d +/begin/r ${tempfile} +}" docs/config.md + rm -f "${tempfile}" +} + function usage { echo >&2 "Usage:" echo >&2 " $0 build" @@ -498,6 +512,8 @@ function usage { echo >&2 " $0 vsh" echo >&2 " $0 stop" echo >&2 " $0 clean" + echo >&2 " $0 update-bindata" + echo >&2 " $0 update-docs" echo >&2 " $0 gotest [TEST_ARGS...]" echo >&2 " $0 gobuild [BUILD_ARGS...]" echo >&2 " $0 run CMD..." @@ -551,6 +567,14 @@ case "${cmd}" in update-bindata-internal) update_bindata_internal ;; + update-docs) + vcmd "build/cmd.sh update-docs-internal" + rm -rf "${project_dir}/docs/virtletctl" + docker exec virtlet-build tar -C "${remote_project_dir}" -c docs/config.md docs/virtletctl | tar -C "${project_dir}" -xv + ;; + update-docs-internal) + update_docs_internal + ;; run) vcmd "$*" ;; From 4aaf925e0306445f016731084f4745ec6dac4310 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:25:24 +0300 Subject: [PATCH 13/17] Update build tool docs --- docs/devel/build-tool.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/devel/build-tool.md b/docs/devel/build-tool.md index 9fef22290..5e7db2f52 100644 --- a/docs/devel/build-tool.md +++ b/docs/devel/build-tool.md @@ -112,6 +112,15 @@ by CI. Starts the build container. This is done automatically by other `build/cmd.sh` commands that need the build container. +### update-bindata + +Updates the generated bindata. Run this command if you modify +anything under `deploy/data`. + +### update-docs + +Updates the documentation on virtletctl an the Virtlet config. + ### e2e Runs Virtlet e2e tests against the currently running DIND cluster. From 0737678f477cf254e7c279484d93cf42dacec7fd Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:26:32 +0300 Subject: [PATCH 14/17] Add per-node config doc --- deploy/README.md | 3 + deploy/real-cluster.md | 5 + docs/config.md | 104 ++++++++++++++++++++ docs/virtletctl/virtletctl.md | 2 +- docs/virtletctl/virtletctl_dump-metadata.md | 2 +- docs/virtletctl/virtletctl_gen.md | 3 +- docs/virtletctl/virtletctl_gendoc.md | 7 +- docs/virtletctl/virtletctl_install.md | 2 +- docs/virtletctl/virtletctl_ssh.md | 2 +- docs/virtletctl/virtletctl_version.md | 2 +- docs/virtletctl/virtletctl_virsh.md | 2 +- docs/virtletctl/virtletctl_vnc.md | 2 +- 12 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 docs/config.md diff --git a/deploy/README.md b/deploy/README.md index 23a2125ed..c2c170ea4 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -75,6 +75,9 @@ by Virtlet when it's deployed using k8s yaml produced by `virtletctl gen`: * `image_regexp_translation` - enables regexp syntax for the image name translation rules. * `disable_logging` - disables log streaming from VMs. Use "1" to disable. +It's also possible to set [per-node configuration](../docs/config.md) +for Virtlet using CRDs. + ## Removing Virtlet In order to remove Virtlet, first you need to delete all the VM pods. diff --git a/deploy/real-cluster.md b/deploy/real-cluster.md index 1206316cd..0a86711f8 100644 --- a/deploy/real-cluster.md +++ b/deploy/real-cluster.md @@ -154,3 +154,8 @@ changes in Kubelet flags, e.g. by removing kubeadm scenario described above. After this you need to restart kubelet and remove the CRI Proxy binary (`/usr/local/bin/criproxy`) and its node configuration file (`/etc/criproxy/node.conf`). + +## Customizing Virtlet per-node configuration + +It's possible to specify per-node configuration options for Virtlet. +See [this document](../docs/config.md) for more information. diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 000000000..42cacf020 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,104 @@ +# Virtlet configuration + +Virtlet has a flexible configuration mechanism that makes it possible +to specify per-node configuration using CRDs. + +## Using per-node configuration + +In order to use per-node configuration, you need to create Virtlet +CRD definitions before you deploy Virtlet: + +```bash +virtletctl gen --crd | kubectl apply -f - +``` + +After that, you can add one or more Virtlet configuration mappings: +```bash +kubectl apply -f - < + +| Description | Config field | Default value | Type | Command line flag / Env | +| --- | --- | --- | --- | --- | +| Path to fd server socket | `fdServerSocketPath` | `/var/lib/virtlet/tapfdserver.sock` | string | `--fd-server-socket-path` / `VIRTLET_FD_SERVER_SOCKET_PATH` | +| Path to the virtlet database | `databasePath` | `/var/lib/virtlet/virtlet.db` | string | `--database-path` / `VIRTLET_DATABASE_PATH` | +| Image download protocol. Can be https or http | `downloadProtocol` | `https` | string | `--image-download-protocol` / `VIRTLET_DOWNLOAD_PROTOCOL` | +| Image directory | `imageDir` | `/var/lib/virtlet/images` | string | `--image-dir` / `VIRTLET_IMAGE_DIR` | +| Image name translation configs directory | `imageTranslationConfigsDir` | `/etc/virtlet/images` | string | `--image-translation-configs-dir` / `VIRTLET_IMAGE_TRANSLATIONS_DIR` | +| Libvirt connection URI | `libvirtURI` | `qemu:///system` | string | `--libvirt-uri` / `VIRTLET_LIBVIRT_URI` | +| Comma separated list of raw device glob patterns which VMs can access (without '/dev/' prefix) | `rawDevices` | `loop*` | string | `--raw-devices` / `VIRTLET_RAW_DEVICES` | +| The path to UNIX domain socket for CRI service to listen on | `criSocketPath` | `/run/virtlet.sock` | string | `--listen` / `VIRTLET_CRI_SOCKET_PATH` | +| Display logging and the streamer | `disableLogging` | `false` | boolean | `--disable-logging` / `VIRTLET_DISABLE_LOGGING` | +| Forcibly disable KVM support | `disableKVM` | `false` | boolean | `--disable-kvm` / `VIRTLET_DISABLE_KVM` | +| Enable SR-IOV support | `enableSriov` | `false` | boolean | `--enable-sriov` / `VIRTLET_SRIOV_SUPPORT` | +| Path to CNI plugin binaries | `cniPluginDir` | `/opt/cni/bin` | string | `--cni-bin-dir` / `VIRTLET_CNI_PLUGIN_DIR` | +| Path to the CNI configuration directory | `cniConfigDir` | `/etc/cni/net.d` | string | `--cni-conf-dir` / `VIRTLET_CNI_CONFIG_DIR` | +| Calico subnet size to use | `calicoSubnetSize` | `24` | integer | `--calico-subnet-size` / `VIRTLET_CALICO_SUBNET` | +| Enable regexp image name translation | `enableRegexpImageTranslation` | `true` | boolean | `--enable-regexp-image-translation` / `IMAGE_REGEXP_TRANSLATION` | +| Log level to use | `logLevel` | `1` | integer | `--v` / `VIRTLET_LOGLEVEL` | + + +Only the following config fields mentioned in this table can be used +with standard Virtlet deployment YAML: `downloadProtocol`, +`rawDevices`, `disableKVM`, `enableSriov`, `calicoSubnetSize`, +`enableRegexpImageTranslation` and `logLevel`. Other options may need +adjusting the YAML to change the paths of volume +mounts. `disableLogging` option is intended for debugging purposes +only. diff --git a/docs/virtletctl/virtletctl.md b/docs/virtletctl/virtletctl.md index 3949b752c..d1d13a3bd 100644 --- a/docs/virtletctl/virtletctl.md +++ b/docs/virtletctl/virtletctl.md @@ -49,4 +49,4 @@ Kubernetes cluster. * [virtletctl virsh](virtletctl_virsh.md) - Execute a virsh command * [virtletctl vnc](virtletctl_vnc.md) - Provide access to the VNC console of a VM pod -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_dump-metadata.md b/docs/virtletctl/virtletctl_dump-metadata.md index ece7c778b..1abb8ad4c 100644 --- a/docs/virtletctl/virtletctl_dump-metadata.md +++ b/docs/virtletctl/virtletctl_dump-metadata.md @@ -51,4 +51,4 @@ virtletctl dump-metadata [flags] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_gen.md b/docs/virtletctl/virtletctl_gen.md index b362aedf6..7ed6d91e7 100644 --- a/docs/virtletctl/virtletctl_gen.md +++ b/docs/virtletctl/virtletctl_gen.md @@ -14,6 +14,7 @@ virtletctl gen [flags] ``` --compat Produce YAML that's compatible with older Kubernetes versions + --crd Dump CRD definitions only --dev Development mode for use with kubeadm-dind-cluster -h, --help help for gen --tag string Set virtlet image tag @@ -52,4 +53,4 @@ virtletctl gen [flags] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_gendoc.md b/docs/virtletctl/virtletctl_gendoc.md index f66680d93..4f1fd647e 100644 --- a/docs/virtletctl/virtletctl_gendoc.md +++ b/docs/virtletctl/virtletctl_gendoc.md @@ -4,7 +4,7 @@ Generate Markdown documentation for the commands ### Synopsis -This command produces documentation for the whole command tree. +This command produces documentation for the whole command tree, or the Virtlet configuration data. ``` virtletctl gendoc output_dir [flags] @@ -13,7 +13,8 @@ virtletctl gendoc output_dir [flags] ### Options ``` - -h, --help help for gendoc + --config Produce documentation for Virtlet config + -h, --help help for gendoc ``` ### Options inherited from parent commands @@ -49,4 +50,4 @@ virtletctl gendoc output_dir [flags] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_install.md b/docs/virtletctl/virtletctl_install.md index 830148301..7e397ca55 100644 --- a/docs/virtletctl/virtletctl_install.md +++ b/docs/virtletctl/virtletctl_install.md @@ -53,4 +53,4 @@ virtletctl install [flags] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_ssh.md b/docs/virtletctl/virtletctl_ssh.md index dd7744039..8bf26cf29 100644 --- a/docs/virtletctl/virtletctl_ssh.md +++ b/docs/virtletctl/virtletctl_ssh.md @@ -51,4 +51,4 @@ virtletctl ssh [flags] user@pod -- [ssh args...] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_version.md b/docs/virtletctl/virtletctl_version.md index b0c6dfb70..a77ffaafc 100644 --- a/docs/virtletctl/virtletctl_version.md +++ b/docs/virtletctl/virtletctl_version.md @@ -52,4 +52,4 @@ virtletctl version [flags] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_virsh.md b/docs/virtletctl/virtletctl_virsh.md index ec0423dfe..cd2ecaa2b 100644 --- a/docs/virtletctl/virtletctl_virsh.md +++ b/docs/virtletctl/virtletctl_virsh.md @@ -59,4 +59,4 @@ virtletctl virsh [flags] virsh_command -- [virsh_command_args...] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 diff --git a/docs/virtletctl/virtletctl_vnc.md b/docs/virtletctl/virtletctl_vnc.md index af627e7c8..fbf9697c2 100644 --- a/docs/virtletctl/virtletctl_vnc.md +++ b/docs/virtletctl/virtletctl_vnc.md @@ -55,4 +55,4 @@ virtletctl vnc pod [port] [flags] * [virtletctl](virtletctl.md) - Virtlet control tool -###### Auto generated by spf13/cobra on 16-May-2018 +###### Auto generated by spf13/cobra on 11-Jun-2018 From bf50cf09dc8edc3d296a759ebae7f5c705d0f645 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:28:44 +0300 Subject: [PATCH 15/17] Add VIRTLET_MULTI_NODE support to demo.sh --- deploy/demo.sh | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/deploy/demo.sh b/deploy/demo.sh index 9526549b6..59db29e1d 100755 --- a/deploy/demo.sh +++ b/deploy/demo.sh @@ -16,6 +16,7 @@ RELEASE_LOCATION="${RELEASE_LOCATION:-https://github.com/Mirantis/virtlet/releas VIRTLET_DEMO_RELEASE="${VIRTLET_DEMO_RELEASE:-}" VIRTLET_DEMO_BRANCH="${VIRTLET_DEMO_BRANCH:-}" VIRTLET_ON_MASTER="${VIRTLET_ON_MASTER:-}" +VIRTLET_MULTI_NODE="${VIRTLET_MULTI_NODE:-}" IMAGE_REGEXP_TRANSLATION="${IMAGE_REGEXP_TRANSLATION:-1}" # Convenience setting for local testing: # BASE_LOCATION="${HOME}/work/kubernetes/src/github.com/Mirantis/virtlet" @@ -24,11 +25,16 @@ cirros_key="demo-cirros-private-key" declare virtlet_release declare virtlet_docker_tag -virtlet_node=kube-node-1 +virtlet_nodes=() if [[ ${VIRTLET_ON_MASTER} ]]; then - virtlet_node=kube-master + virtlet_nodes+=(kube-master) +fi +if [[ !${VIRTLET_ON_MASTER} || ${VIRTLET_MULTI_NODE} ]]; then + virtlet_nodes+=(kube-node-1) +fi +if [[ ${VIRTLET_MULTI_NODE} ]]; then + virtlet_nodes+=(kube-node-2) fi - # In case of linuxkit / moby linux, -v will not work so we can't # mount /lib/modules and /boot. @@ -130,11 +136,13 @@ function demo::start-dind-cluster { } function demo::install-cri-proxy { + local virtlet_node="${1}" demo::step "Installing CRI proxy package on ${virtlet_node} container" docker exec "${virtlet_node}" /bin/bash -c "curl -sSL '${CRIPROXY_DEB_URL}' >/criproxy.deb && dpkg -i /criproxy.deb && rm /criproxy.deb" } function demo::fix-mounts { + local virtlet_node="${1}" demo::step "Marking mounts used by virtlet as shared in ${virtlet_node} container" docker exec "${virtlet_node}" mount --make-shared /dind docker exec "${virtlet_node}" mount --make-shared /dev @@ -145,11 +153,13 @@ function demo::fix-mounts { } function demo::inject-local-image { + local virtlet_node="${1}" demo::step "Copying local mirantis/virtlet image into ${virtlet_node} container" docker save mirantis/virtlet | docker exec -i "${virtlet_node}" docker load } function demo::label-and-untaint-node { + local virtlet_node="${1}" demo::step "Applying label to ${virtlet_node}:" "extraRuntime=virtlet" "${kubectl}" label node "${virtlet_node}" extraRuntime=virtlet if [[ ${VIRTLET_ON_MASTER} ]]; then @@ -265,7 +275,8 @@ function demo::kvm-ok { if [[ ${using_linuxkit} ]]; then return 1 fi - if ! docker exec "${virtlet_node}" docker run --privileged --rm -v /lib/modules:/lib/modules "mirantis/virtlet:${virtlet_docker_tag}" kvm-ok; then + # use kube-master node as all of the DIND nodes in the cluster are similar + if ! docker exec kube-master docker run --privileged --rm -v /lib/modules:/lib/modules "mirantis/virtlet:${virtlet_docker_tag}" kvm-ok; then return 1 fi } @@ -368,12 +379,14 @@ fi demo::get-dind-cluster demo::start-dind-cluster -demo::fix-mounts -demo::install-cri-proxy -if [[ ${INJECT_LOCAL_IMAGE:-} ]]; then - demo::inject-local-image -fi -demo::label-and-untaint-node +for virtlet_node in "${virtlet_nodes[@]}"; do + demo::fix-mounts "${virtlet_node}" + demo::install-cri-proxy "${virtlet_node}" + if [[ ${INJECT_LOCAL_IMAGE:-} ]]; then + demo::inject-local-image "${virtlet_node}" + fi + demo::label-and-untaint-node "${virtlet_node}" +done demo::start-virtlet demo::start-nginx demo::start-vm From 0677a9ac07bb838b515344ab8df63c28d096df5f Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:37:52 +0300 Subject: [PATCH 16/17] Add a test for 'global' VirtletConfigMapping Make sure config mappings w/o nodeSelector and nodeName apply to all nodes. --- .../TestConfigForNode__global_mapping.out.yaml | 17 +++++++++++++++++ pkg/config/config_test.go | 9 ++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100755 pkg/config/TestConfigForNode__global_mapping.out.yaml diff --git a/pkg/config/TestConfigForNode__global_mapping.out.yaml b/pkg/config/TestConfigForNode__global_mapping.out.yaml new file mode 100755 index 000000000..19dce3550 --- /dev/null +++ b/pkg/config/TestConfigForNode__global_mapping.out.yaml @@ -0,0 +1,17 @@ +calicoSubnetSize: 22 +cniConfigDir: /some/cni/conf/dir +cniPluginDir: /some/cni/bin/dir +criSocketPath: /some/cri.sock +databasePath: /some/file.db +disableKVM: true +disableLogging: true +downloadProtocol: http +enableRegexpImageTranslation: false +enableSriov: true +fdServerSocketPath: /some/fd/server.sock +imageDir: /var/lib/virtlet/images +imageTranslationConfigsDir: /some/translation/dir +libvirtURI: qemu:///foobar +logLevel: 3 +rawDevices: sd* +skipImageTranslation: false diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 208062030..1a8083832 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -192,7 +192,8 @@ spec: spec: nodeSelector: label-a: "1"` + fullConfig - anotherMapping1 = ` + globalFullMapping = "spec:" + fullConfig + anotherMapping1 = ` spec: nodeName: kube-node-1 priority: 10 @@ -260,6 +261,12 @@ func TestConfigForNode(t *testing.T) { nodeLabels: map[string]string{"label-x": "1"}, mappings: []string{labelAFullMapping}, }, + { + name: "global mapping", + nodeName: "kube-node-1", + nodeLabels: map[string]string{"label-a": "1"}, + mappings: []string{globalFullMapping}, + }, { name: "mapping by node name and multiple labels", nodeName: "kube-node-1", From c940c348447e0d62686d7a6d523727f4637c9202 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 12 Jun 2018 03:44:43 +0300 Subject: [PATCH 17/17] Fix style issues --- .codeclimate.yml | 2 ++ cmd/virtlet/virtlet.go | 4 ++-- pkg/api/virtlet.k8s/v1/doc.go | 1 - pkg/api/virtlet.k8s/v1/register.go | 8 +++++--- pkg/config/config.go | 20 ++++++++++---------- pkg/config/config_test.go | 4 ++-- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index a7fd3c1b4..1eb2cdd5e 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -50,3 +50,5 @@ exclude_patterns: # CRI fields / consts, but make CodeClimate unhappy due to # underscores and "Id" instead of "ID" - "pkg/metadata/types/types.go" + # gofmt issue in the generated code + - "pkg/client/clientset/versioned/clientset.go" diff --git a/cmd/virtlet/virtlet.go b/cmd/virtlet/virtlet.go index 41c070ee5..9840b7e9c 100644 --- a/cmd/virtlet/virtlet.go +++ b/cmd/virtlet/virtlet.go @@ -124,8 +124,8 @@ func setLogLevel(config *v1.VirtletConfig) { func main() { utils.HandleNsFixReexec() clientCfg := utils.BindFlags(flag.CommandLine) - var cb *config.ConfigBinder - cb = config.NewConfigBinder(flag.CommandLine) + var cb *config.Binder + cb = config.NewBinder(flag.CommandLine) flag.Parse() localConfig := cb.GetConfig() diff --git a/pkg/api/virtlet.k8s/v1/doc.go b/pkg/api/virtlet.k8s/v1/doc.go index b2b67a60f..4d5a47467 100644 --- a/pkg/api/virtlet.k8s/v1/doc.go +++ b/pkg/api/virtlet.k8s/v1/doc.go @@ -18,5 +18,4 @@ limitations under the License. // Package v1 is the v1 version of the API. // +groupName=virtlet.k8s - package v1 diff --git a/pkg/api/virtlet.k8s/v1/register.go b/pkg/api/virtlet.k8s/v1/register.go index c7d1652bd..2b875ca1e 100644 --- a/pkg/api/virtlet.k8s/v1/register.go +++ b/pkg/api/virtlet.k8s/v1/register.go @@ -28,10 +28,12 @@ const ( ) var ( - schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - scheme = runtime.NewScheme() + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + scheme = runtime.NewScheme() + // SchemeGroupVersion is group version used to register the objects SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: version} - AddToScheme = schemeBuilder.AddToScheme + // AddToScheme adds the objects to the scheme + AddToScheme = schemeBuilder.AddToScheme ) // Resource takes an unqualified resource and returns a Group qualified GroupResource. diff --git a/pkg/config/config.go b/pkg/config/config.go index 662c2751a..03805326e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -138,7 +138,7 @@ func mappingMatches(cm virtlet_v1.VirtletConfigMapping, nodeName string, nodeLab return true } -// MergeConfig merges several Virtlet configs together, with +// MergeConfigs merges several Virtlet configs together, with // configs going later taking precedence. func MergeConfigs(configs []*virtlet_v1.VirtletConfig) *virtlet_v1.VirtletConfig { var cfg *virtlet_v1.VirtletConfig @@ -152,23 +152,23 @@ func MergeConfigs(configs []*virtlet_v1.VirtletConfig) *virtlet_v1.VirtletConfig return cfg } -// ConfigBinder is used to extract Virtlet config from a FlagSet. -type ConfigBinder struct { +// Binder is used to extract Virtlet config from a FlagSet. +type Binder struct { flagSet *flag.FlagSet config *virtlet_v1.VirtletConfig fieldSet *fieldSet lookupEnv envLookup } -// NewConfigBinder returns a new ConfigBinder. -func NewConfigBinder(flagSet *flag.FlagSet) *ConfigBinder { +// NewBinder returns a new Binder. +func NewBinder(flagSet *flag.FlagSet) *Binder { config := &virtlet_v1.VirtletConfig{} fs := configFieldSet(config) fs.applyDefaults() if flagSet != nil { fs.addFlags(flagSet) } - return &ConfigBinder{ + return &Binder{ flagSet: flagSet, config: config, fieldSet: fs, @@ -178,10 +178,10 @@ func NewConfigBinder(flagSet *flag.FlagSet) *ConfigBinder { // GetConfig returns the config that only includes the fields that // were explicitly set in the flags. It should be called after parsing // the flags. -func (cb *ConfigBinder) GetConfig() *virtlet_v1.VirtletConfig { - cb.fieldSet.clearFieldsNotInFlagSet(cb.flagSet) - cb.fieldSet.setFromEnv(cb.lookupEnv) - return cb.config +func (b *Binder) GetConfig() *virtlet_v1.VirtletConfig { + b.fieldSet.clearFieldsNotInFlagSet(b.flagSet) + b.fieldSet.setFromEnv(b.lookupEnv) + return b.config } // configForNode gets virtlet_v1.VirtletConfig for the specified node name and labels. diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 1a8083832..ebc456c46 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -61,7 +61,7 @@ func verifyEnv(t *testing.T, c *virtlet_v1.VirtletConfig) { fakeEnv[parts[1]] = subparts[0] } } - binder := NewConfigBinder(nil) + binder := NewBinder(nil) binder.lookupEnv = func(name string) (string, bool) { r, found := fakeEnv[name] return r, found @@ -153,7 +153,7 @@ func TestMergeConfigs(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { flags := flag.NewFlagSet("virtlet", flag.ContinueOnError) - configBinder := NewConfigBinder(flags) + configBinder := NewBinder(flags) if err := flags.Parse(strings.Split(tc.args, " ")); err != nil { t.Fatalf("error parsing flags: %v", err) }