From 8e32b6b15d35aa99883ac24ce610c3d01e6fa1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Mart=C3=ADn?= Date: Thu, 13 Jul 2023 16:44:28 +0200 Subject: [PATCH] openstack: fix project sync for new authentication methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The project list will retrieve user projects only as users usually lack permissions for the 'list_projects' operation in nova. Currently, we only allow migrations from the project associated with the session/token/applicationcredential so it makes no sense to sync other projects The current implementation takes the project name from the secret. This property maybe missing if token or applicationcredentials authentication is used so we need to figure out the project depending on the authentication type and which fields are required in each case. Signed-off-by: Miguel Martín --- .../provider/container/openstack/BUILD.bazel | 1 + .../provider/container/openstack/client.go | 55 ++-- .../v3/applicationcredentials/BUILD.bazel | 17 ++ .../v3/applicationcredentials/requests.go | 136 +++++++++ .../v3/applicationcredentials/results.go | 201 ++++++++++++ .../v3/applicationcredentials/urls.go | 31 ++ vendor/modules.txt | 2 +- .../pkg/log/zap/BUILD.bazel | 23 -- .../controller-runtime/pkg/log/zap/flags.go | 130 -------- .../pkg/log/zap/kube_helpers.go | 127 -------- .../controller-runtime/pkg/log/zap/zap.go | 287 ------------------ 11 files changed, 419 insertions(+), 591 deletions(-) create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/BUILD.bazel create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/BUILD.bazel delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go diff --git a/pkg/controller/provider/container/openstack/BUILD.bazel b/pkg/controller/provider/container/openstack/BUILD.bazel index 859730198..7f3f0fbd3 100644 --- a/pkg/controller/provider/container/openstack/BUILD.bazel +++ b/pkg/controller/provider/container/openstack/BUILD.bazel @@ -31,6 +31,7 @@ go_library( "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumetypes", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers", + "//vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials", "//vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/projects", "//vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/regions", "//vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", diff --git a/pkg/controller/provider/container/openstack/client.go b/pkg/controller/provider/container/openstack/client.go index ec8c6904c..38ac21821 100644 --- a/pkg/controller/provider/container/openstack/client.go +++ b/pkg/controller/provider/container/openstack/client.go @@ -18,6 +18,7 @@ import ( "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumetypes" "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors" "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" + "github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials" "github.com/gophercloud/gophercloud/openstack/identity/v3/projects" "github.com/gophercloud/gophercloud/openstack/identity/v3/regions" "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" @@ -301,31 +302,10 @@ func (r *Client) list(object interface{}, listopts interface{}) (err error) { case *[]Project: object := object.(*[]Project) // TODO implement support multiple regions/projects sync per user - opts := listopts.(*ProjectListOpts) - opts.Name = r.getStringFromSecret(ProjectName) - allPages, err = projects.List(r.identityService, opts).AllPages() - if err != nil { - if !r.isForbidden(err) { - err = liberr.Wrap(err) - return - } - *object, err = r.getUserProjects() - if err != nil { - err = liberr.Wrap(err) - } - return - } - var projectList []projects.Project - projectList, err = projects.ExtractProjects(allPages) + *object, err = r.getUserProjects() if err != nil { err = liberr.Wrap(err) - return } - var instanceList []Project - for _, project := range projectList { - instanceList = append(instanceList, Project{project}) - } - *object = instanceList return case *[]Flavor: @@ -699,9 +679,38 @@ func (r *Client) getUserProjects() (userProjects []Project, err error) { err = liberr.Wrap(err) return } + + projectName := r.getStringFromSecret(ProjectName) + projectID := r.getStringFromSecret(ProjectID) + + if projectName == "" && projectID == "" { + applicationCredentialID := r.getStringFromSecret(ApplicationCredentialID) + if applicationCredentialID != "" { + var applicationCredential *applicationcredentials.ApplicationCredential + applicationCredential, err = applicationcredentials.Get(r.identityService, userID, applicationCredentialID).Extract() + if err != nil { + err = liberr.Wrap(err) + return + } + projectID = applicationCredential.ProjectID + } + applicationCredentialName := r.getStringFromSecret(ApplicationCredentialName) + if applicationCredentialName != "" { + var applicationCredentials []applicationcredentials.ApplicationCredential + allPages, err = applicationcredentials.List(r.identityService, userID, &applicationcredentials.ListOpts{Name: applicationCredentialName}).AllPages() + if err != nil { + err = liberr.Wrap(err) + return + } + applicationCredentials, err = applicationcredentials.ExtractApplicationCredentials(allPages) + projectID = applicationCredentials[0].ProjectID + } + + } + for _, project := range projectList { // TODO implement support multiple regions/projects sync per user - if project.Name == r.getStringFromSecret(ProjectName) { + if project.Name == projectName || project.ID == projectID { userProjects = append(userProjects, Project{project}) } } diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/BUILD.bazel b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/BUILD.bazel new file mode 100644 index 000000000..73f40742d --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/BUILD.bazel @@ -0,0 +1,17 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "applicationcredentials", + srcs = [ + "requests.go", + "results.go", + "urls.go", + ], + importmap = "github.com/konveyor/forklift-controller/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials", + importpath = "github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/gophercloud/gophercloud", + "//vendor/github.com/gophercloud/gophercloud/pagination", + ], +) diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go new file mode 100644 index 000000000..be62af7f7 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go @@ -0,0 +1,136 @@ +package applicationcredentials + +import ( + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// ListOptsBuilder allows extensions to add additional parameters to +// the List request +type ListOptsBuilder interface { + ToApplicationCredentialListQuery() (string, error) +} + +// ListOpts provides options to filter the List results. +type ListOpts struct { + // Name filters the response by an application credential name + Name string `q:"name"` +} + +// ToApplicationCredentialListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToApplicationCredentialListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List enumerates the ApplicationCredentials to which the current token has access. +func List(client *gophercloud.ServiceClient, userID string, opts ListOptsBuilder) pagination.Pager { + url := listURL(client, userID) + if opts != nil { + query, err := opts.ToApplicationCredentialListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return ApplicationCredentialPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Get retrieves details on a single user, by ID. +func Get(client *gophercloud.ServiceClient, userID string, id string) (r GetResult) { + resp, err := client.Get(getURL(client, userID, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// CreateOptsBuilder allows extensions to add additional parameters to +// the Create request. +type CreateOptsBuilder interface { + ToApplicationCredentialCreateMap() (map[string]interface{}, error) +} + +// CreateOpts provides options used to create an application credential. +type CreateOpts struct { + // The name of the application credential. + Name string `json:"name,omitempty" required:"true"` + // A description of the application credential’s purpose. + Description string `json:"description,omitempty"` + // A flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts. + // Defaults to false + Unrestricted bool `json:"unrestricted"` + // The secret for the application credential, either generated by the server or provided by the user. + // This is only ever shown once in the response to a create request. It is not stored nor ever shown again. + // If the secret is lost, a new application credential must be created. + Secret string `json:"secret,omitempty"` + // A list of one or more roles that this application credential has associated with its project. + // A token using this application credential will have these same roles. + Roles []Role `json:"roles,omitempty"` + // A list of access rules objects. + AccessRules []AccessRule `json:"access_rules,omitempty"` + // The expiration time of the application credential, if one was specified. + ExpiresAt *time.Time `json:"-"` +} + +// ToApplicationCredentialCreateMap formats a CreateOpts into a create request. +func (opts CreateOpts) ToApplicationCredentialCreateMap() (map[string]interface{}, error) { + parent := "application_credential" + b, err := gophercloud.BuildRequestBody(opts, parent) + if err != nil { + return nil, err + } + + if opts.ExpiresAt != nil { + if v, ok := b[parent].(map[string]interface{}); ok { + v["expires_at"] = opts.ExpiresAt.Format(gophercloud.RFC3339MilliNoZ) + } + } + + return b, nil +} + +// Create creates a new ApplicationCredential. +func Create(client *gophercloud.ServiceClient, userID string, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToApplicationCredentialCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Post(createURL(client, userID), &b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{201}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Delete deletes an application credential. +func Delete(client *gophercloud.ServiceClient, userID string, id string) (r DeleteResult) { + resp, err := client.Delete(deleteURL(client, userID, id), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// ListAccessRules enumerates the AccessRules to which the current user has access. +func ListAccessRules(client *gophercloud.ServiceClient, userID string) pagination.Pager { + url := listAccessRulesURL(client, userID) + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return AccessRulePage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// GetAccessRule retrieves details on a single access rule by ID. +func GetAccessRule(client *gophercloud.ServiceClient, userID string, id string) (r GetAccessRuleResult) { + resp, err := client.Get(getAccessRuleURL(client, userID, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// DeleteAccessRule deletes an access rule. +func DeleteAccessRule(client *gophercloud.ServiceClient, userID string, id string) (r DeleteResult) { + resp, err := client.Delete(deleteAccessRuleURL(client, userID, id), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go new file mode 100644 index 000000000..8ed389d13 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go @@ -0,0 +1,201 @@ +package applicationcredentials + +import ( + "encoding/json" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +type Role struct { + // DomainID is the domain ID the role belongs to. + DomainID string `json:"domain_id,omitempty"` + // ID is the unique ID of the role. + ID string `json:"id,omitempty"` + // Name is the role name + Name string `json:"name,omitempty"` +} + +// ApplicationCredential represents the access rule object +type AccessRule struct { + // The ID of the access rule + ID string `json:"id,omitempty"` + // The API path that the application credential is permitted to access + Path string `json:"path,omitempty"` + // The request method that the application credential is permitted to use for a + // given API endpoint + Method string `json:"method,omitempty"` + // The service type identifier for the service that the application credential + // is permitted to access + Service string `json:"service,omitempty"` +} + +// ApplicationCredential represents the application credential object +type ApplicationCredential struct { + // The ID of the application credential. + ID string `json:"id"` + // The name of the application credential. + Name string `json:"name"` + // A description of the application credential’s purpose. + Description string `json:"description"` + // A flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts. + // Defaults to false + Unrestricted bool `json:"unrestricted"` + // The secret for the application credential, either generated by the server or provided by the user. + // This is only ever shown once in the response to a create request. It is not stored nor ever shown again. + // If the secret is lost, a new application credential must be created. + Secret string `json:"secret"` + // The ID of the project the application credential was created for and that authentication requests using this application credential will be scoped to. + ProjectID string `json:"project_id"` + // A list of one or more roles that this application credential has associated with its project. + // A token using this application credential will have these same roles. + Roles []Role `json:"roles"` + // The expiration time of the application credential, if one was specified. + ExpiresAt time.Time `json:"-"` + // A list of access rules objects. + AccessRules []AccessRule `json:"access_rules,omitempty"` + // Links contains referencing links to the application credential. + Links map[string]interface{} `json:"links"` +} + +func (r *ApplicationCredential) UnmarshalJSON(b []byte) error { + type tmp ApplicationCredential + var s struct { + tmp + ExpiresAt gophercloud.JSONRFC3339MilliNoZ `json:"expires_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = ApplicationCredential(s.tmp) + + r.ExpiresAt = time.Time(s.ExpiresAt) + + return nil +} + +type applicationCredentialResult struct { + gophercloud.Result +} + +// GetResult is the response from a Get operation. Call its Extract method +// to interpret it as an ApplicationCredential. +type GetResult struct { + applicationCredentialResult +} + +// CreateResult is the response from a Create operation. Call its Extract method +// to interpret it as an ApplicationCredential. +type CreateResult struct { + applicationCredentialResult +} + +// DeleteResult is the response from a Delete operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} + +// an ApplicationCredentialPage is a single page of an ApplicationCredential results. +type ApplicationCredentialPage struct { + pagination.LinkedPageBase +} + +// IsEmpty determines whether or not a an ApplicationCredentialPage contains any results. +func (r ApplicationCredentialPage) IsEmpty() (bool, error) { + if r.StatusCode == 204 { + return true, nil + } + + applicationCredentials, err := ExtractApplicationCredentials(r) + return len(applicationCredentials) == 0, err +} + +// NextPageURL extracts the "next" link from the links section of the result. +func (r ApplicationCredentialPage) NextPageURL() (string, error) { + var s struct { + Links struct { + Next string `json:"next"` + Previous string `json:"previous"` + } `json:"links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return s.Links.Next, err +} + +// Extractan ApplicationCredentials returns a slice of ApplicationCredentials contained in a single page of results. +func ExtractApplicationCredentials(r pagination.Page) ([]ApplicationCredential, error) { + var s struct { + ApplicationCredentials []ApplicationCredential `json:"application_credentials"` + } + err := (r.(ApplicationCredentialPage)).ExtractInto(&s) + return s.ApplicationCredentials, err +} + +// Extract interprets any application_credential results as an ApplicationCredential. +func (r applicationCredentialResult) Extract() (*ApplicationCredential, error) { + var s struct { + ApplicationCredential *ApplicationCredential `json:"application_credential"` + } + err := r.ExtractInto(&s) + return s.ApplicationCredential, err +} + +// GetAccessRuleResult is the response from a Get operation. Call its Extract method +// to interpret it as an AccessRule. +type GetAccessRuleResult struct { + gophercloud.Result +} + +// an AccessRulePage is a single page of an AccessRule results. +type AccessRulePage struct { + pagination.LinkedPageBase +} + +// IsEmpty determines whether or not a an AccessRulePage contains any results. +func (r AccessRulePage) IsEmpty() (bool, error) { + if r.StatusCode == 204 { + return true, nil + } + + accessRules, err := ExtractAccessRules(r) + return len(accessRules) == 0, err +} + +// NextPageURL extracts the "next" link from the links section of the result. +func (r AccessRulePage) NextPageURL() (string, error) { + var s struct { + Links struct { + Next string `json:"next"` + Previous string `json:"previous"` + } `json:"links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return s.Links.Next, err +} + +// ExtractAccessRules returns a slice of AccessRules contained in a single page of results. +func ExtractAccessRules(r pagination.Page) ([]AccessRule, error) { + var s struct { + AccessRules []AccessRule `json:"access_rules"` + } + err := (r.(AccessRulePage)).ExtractInto(&s) + return s.AccessRules, err +} + +// Extract interprets any access_rule results as an AccessRule. +func (r GetAccessRuleResult) Extract() (*AccessRule, error) { + var s struct { + AccessRule *AccessRule `json:"access_rule"` + } + err := r.ExtractInto(&s) + return s.AccessRule, err +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go new file mode 100644 index 000000000..f809385f2 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go @@ -0,0 +1,31 @@ +package applicationcredentials + +import "github.com/gophercloud/gophercloud" + +func listURL(client *gophercloud.ServiceClient, userID string) string { + return client.ServiceURL("users", userID, "application_credentials") +} + +func getURL(client *gophercloud.ServiceClient, userID string, id string) string { + return client.ServiceURL("users", userID, "application_credentials", id) +} + +func createURL(client *gophercloud.ServiceClient, userID string) string { + return client.ServiceURL("users", userID, "application_credentials") +} + +func deleteURL(client *gophercloud.ServiceClient, userID string, id string) string { + return client.ServiceURL("users", userID, "application_credentials", id) +} + +func listAccessRulesURL(client *gophercloud.ServiceClient, userID string) string { + return client.ServiceURL("users", userID, "access_rules") +} + +func getAccessRuleURL(client *gophercloud.ServiceClient, userID string, id string) string { + return client.ServiceURL("users", userID, "access_rules", id) +} + +func deleteAccessRuleURL(client *gophercloud.ServiceClient, userID string, id string) string { + return client.ServiceURL("users", userID, "access_rules", id) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 8a8a9c12c..dea878f30 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -99,6 +99,7 @@ github.com/gophercloud/gophercloud/openstack/compute/v2/flavors github.com/gophercloud/gophercloud/openstack/compute/v2/servers github.com/gophercloud/gophercloud/openstack/identity/v2/tenants github.com/gophercloud/gophercloud/openstack/identity/v2/tokens +github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/ec2tokens github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/oauth1 github.com/gophercloud/gophercloud/openstack/identity/v3/groups @@ -817,7 +818,6 @@ sigs.k8s.io/controller-runtime/pkg/internal/objectutil sigs.k8s.io/controller-runtime/pkg/internal/recorder sigs.k8s.io/controller-runtime/pkg/leaderelection sigs.k8s.io/controller-runtime/pkg/log -sigs.k8s.io/controller-runtime/pkg/log/zap sigs.k8s.io/controller-runtime/pkg/manager sigs.k8s.io/controller-runtime/pkg/manager/signals sigs.k8s.io/controller-runtime/pkg/metrics diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/BUILD.bazel b/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/BUILD.bazel deleted file mode 100644 index 1d9b14ea3..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/BUILD.bazel +++ /dev/null @@ -1,23 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "zap", - srcs = [ - "flags.go", - "kube_helpers.go", - "zap.go", - ], - importmap = "github.com/konveyor/forklift-controller/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap", - importpath = "sigs.k8s.io/controller-runtime/pkg/log/zap", - visibility = ["//visibility:public"], - deps = [ - "//vendor/github.com/go-logr/logr", - "//vendor/github.com/go-logr/zapr", - "//vendor/go.uber.org/zap", - "//vendor/go.uber.org/zap/buffer", - "//vendor/go.uber.org/zap/zapcore", - "//vendor/k8s.io/apimachinery/pkg/api/meta", - "//vendor/k8s.io/apimachinery/pkg/runtime", - "//vendor/k8s.io/apimachinery/pkg/types", - ], -) diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go deleted file mode 100644 index 333965507..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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 zap contains helpers for setting up a new logr.Logger instance -// using the Zap logging framework. -package zap - -import ( - "flag" - "fmt" - "strconv" - "strings" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -var levelStrings = map[string]zapcore.Level{ - "debug": zap.DebugLevel, - "info": zap.InfoLevel, - "error": zap.ErrorLevel, -} - -var stackLevelStrings = map[string]zapcore.Level{ - "info": zap.InfoLevel, - "error": zap.ErrorLevel, - "panic": zap.PanicLevel, -} - -type encoderFlag struct { - setFunc func(NewEncoderFunc) - value string -} - -var _ flag.Value = &encoderFlag{} - -func (ev *encoderFlag) String() string { - return ev.value -} - -func (ev *encoderFlag) Type() string { - return "encoder" -} - -func (ev *encoderFlag) Set(flagValue string) error { - val := strings.ToLower(flagValue) - switch val { - case "json": - ev.setFunc(newJSONEncoder) - case "console": - ev.setFunc(newConsoleEncoder) - default: - return fmt.Errorf("invalid encoder value \"%s\"", flagValue) - } - ev.value = flagValue - return nil -} - -type levelFlag struct { - setFunc func(zapcore.LevelEnabler) - value string -} - -var _ flag.Value = &levelFlag{} - -func (ev *levelFlag) Set(flagValue string) error { - level, validLevel := levelStrings[strings.ToLower(flagValue)] - if !validLevel { - logLevel, err := strconv.Atoi(flagValue) - if err != nil { - return fmt.Errorf("invalid log level \"%s\"", flagValue) - } - if logLevel > 0 { - intLevel := -1 * logLevel - ev.setFunc(zap.NewAtomicLevelAt(zapcore.Level(int8(intLevel)))) - } else { - return fmt.Errorf("invalid log level \"%s\"", flagValue) - } - } else { - ev.setFunc(zap.NewAtomicLevelAt(level)) - } - ev.value = flagValue - return nil -} - -func (ev *levelFlag) String() string { - return ev.value -} - -func (ev *levelFlag) Type() string { - return "level" -} - -type stackTraceFlag struct { - setFunc func(zapcore.LevelEnabler) - value string -} - -var _ flag.Value = &stackTraceFlag{} - -func (ev *stackTraceFlag) Set(flagValue string) error { - level, validLevel := stackLevelStrings[strings.ToLower(flagValue)] - if !validLevel { - return fmt.Errorf("invalid stacktrace level \"%s\"", flagValue) - } - ev.setFunc(zap.NewAtomicLevelAt(level)) - ev.value = flagValue - return nil -} - -func (ev *stackTraceFlag) String() string { - return ev.value -} - -func (ev *stackTraceFlag) Type() string { - return "level" -} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go deleted file mode 100644 index 765327d62..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -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 zap - -import ( - "fmt" - - "go.uber.org/zap/buffer" - "go.uber.org/zap/zapcore" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" -) - -// KubeAwareEncoder is a Kubernetes-aware Zap Encoder. -// Instead of trying to force Kubernetes objects to implement -// ObjectMarshaller, we just implement a wrapper around a normal -// ObjectMarshaller that checks for Kubernetes objects. -type KubeAwareEncoder struct { - // Encoder is the zapcore.Encoder that this encoder delegates to - zapcore.Encoder - - // Verbose controls whether or not the full object is printed. - // If false, only name, namespace, api version, and kind are printed. - // Otherwise, the full object is logged. - Verbose bool -} - -// namespacedNameWrapper is a zapcore.ObjectMarshaler for Kubernetes NamespacedName. -type namespacedNameWrapper struct { - types.NamespacedName -} - -func (w namespacedNameWrapper) MarshalLogObject(enc zapcore.ObjectEncoder) error { - if w.Namespace != "" { - enc.AddString("namespace", w.Namespace) - } - - enc.AddString("name", w.Name) - - return nil -} - -// kubeObjectWrapper is a zapcore.ObjectMarshaler for Kubernetes objects. -type kubeObjectWrapper struct { - obj runtime.Object -} - -// MarshalLogObject implements zapcore.ObjectMarshaler. -func (w kubeObjectWrapper) MarshalLogObject(enc zapcore.ObjectEncoder) error { - // TODO(directxman12): log kind and apiversion if not set explicitly (common case) - // -- needs an a scheme to convert to the GVK. - if gvk := w.obj.GetObjectKind().GroupVersionKind(); gvk.Version != "" { - enc.AddString("apiVersion", gvk.GroupVersion().String()) - enc.AddString("kind", gvk.Kind) - } - - objMeta, err := meta.Accessor(w.obj) - if err != nil { - return fmt.Errorf("got runtime.Object without object metadata: %v", w.obj) - } - - if ns := objMeta.GetNamespace(); ns != "" { - enc.AddString("namespace", ns) - } - enc.AddString("name", objMeta.GetName()) - - return nil -} - -// NB(directxman12): can't just override AddReflected, since the encoder calls AddReflected on itself directly - -// Clone implements zapcore.Encoder. -func (k *KubeAwareEncoder) Clone() zapcore.Encoder { - return &KubeAwareEncoder{ - Encoder: k.Encoder.Clone(), - } -} - -// EncodeEntry implements zapcore.Encoder. -func (k *KubeAwareEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { - if k.Verbose { - // Kubernetes objects implement fmt.Stringer, so if we - // want verbose output, just delegate to that. - return k.Encoder.EncodeEntry(entry, fields) - } - - for i, field := range fields { - // intercept stringer fields that happen to be Kubernetes runtime.Object or - // types.NamespacedName values (Kubernetes runtime.Objects commonly - // implement String, apparently). - // *unstructured.Unstructured does NOT implement fmt.Striger interface. - // We have handle it specially. - if field.Type == zapcore.StringerType || field.Type == zapcore.ReflectType { - switch val := field.Interface.(type) { - case runtime.Object: - fields[i] = zapcore.Field{ - Type: zapcore.ObjectMarshalerType, - Key: field.Key, - Interface: kubeObjectWrapper{obj: val}, - } - case types.NamespacedName: - fields[i] = zapcore.Field{ - Type: zapcore.ObjectMarshalerType, - Key: field.Key, - Interface: namespacedNameWrapper{NamespacedName: val}, - } - } - } - } - - return k.Encoder.EncodeEntry(entry, fields) -} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go deleted file mode 100644 index 22eb5d771..000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go +++ /dev/null @@ -1,287 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -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 zap contains helpers for setting up a new logr.Logger instance -// using the Zap logging framework. -package zap - -import ( - "flag" - "io" - "os" - "time" - - "github.com/go-logr/logr" - "github.com/go-logr/zapr" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// EncoderConfigOption is a function that can modify a `zapcore.EncoderConfig`. -type EncoderConfigOption func(*zapcore.EncoderConfig) - -// NewEncoderFunc is a function that creates an Encoder using the provided EncoderConfigOptions. -type NewEncoderFunc func(...EncoderConfigOption) zapcore.Encoder - -// New returns a brand new Logger configured with Opts. It -// uses KubeAwareEncoder which adds Type information and -// Namespace/Name to the log. -func New(opts ...Opts) logr.Logger { - return zapr.NewLogger(NewRaw(opts...)) -} - -// Opts allows to manipulate Options. -type Opts func(*Options) - -// UseDevMode sets the logger to use (or not use) development mode (more -// human-readable output, extra stack traces and logging information, etc). -// See Options.Development. -func UseDevMode(enabled bool) Opts { - return func(o *Options) { - o.Development = enabled - } -} - -// WriteTo configures the logger to write to the given io.Writer, instead of standard error. -// See Options.DestWriter. -func WriteTo(out io.Writer) Opts { - return func(o *Options) { - o.DestWriter = out - } -} - -// Encoder configures how the logger will encode the output e.g JSON or console. -// See Options.Encoder. -func Encoder(encoder zapcore.Encoder) func(o *Options) { - return func(o *Options) { - o.Encoder = encoder - } -} - -// JSONEncoder configures the logger to use a JSON Encoder. -func JSONEncoder(opts ...EncoderConfigOption) func(o *Options) { - return func(o *Options) { - o.Encoder = newJSONEncoder(opts...) - } -} - -func newJSONEncoder(opts ...EncoderConfigOption) zapcore.Encoder { - encoderConfig := zap.NewProductionEncoderConfig() - for _, opt := range opts { - opt(&encoderConfig) - } - return zapcore.NewJSONEncoder(encoderConfig) -} - -// ConsoleEncoder configures the logger to use a Console encoder. -func ConsoleEncoder(opts ...EncoderConfigOption) func(o *Options) { - return func(o *Options) { - o.Encoder = newConsoleEncoder(opts...) - } -} - -func newConsoleEncoder(opts ...EncoderConfigOption) zapcore.Encoder { - encoderConfig := zap.NewDevelopmentEncoderConfig() - for _, opt := range opts { - opt(&encoderConfig) - } - return zapcore.NewConsoleEncoder(encoderConfig) -} - -// Level sets Options.Level, which configures the the minimum enabled logging level e.g Debug, Info. -// A zap log level should be multiplied by -1 to get the logr verbosity. -// For example, to get logr verbosity of 3, pass zapcore.Level(-3) to this Opts. -// See https://pkg.go.dev/github.com/go-logr/zapr for how zap level relates to logr verbosity. -func Level(level zapcore.LevelEnabler) func(o *Options) { - return func(o *Options) { - o.Level = level - } -} - -// StacktraceLevel sets Options.StacktraceLevel, which configures the logger to record a stack trace -// for all messages at or above a given level. -// See the Level Opts for the relationship of zap log level to logr verbosity. -func StacktraceLevel(stacktraceLevel zapcore.LevelEnabler) func(o *Options) { - return func(o *Options) { - o.StacktraceLevel = stacktraceLevel - } -} - -// RawZapOpts allows appending arbitrary zap.Options to configure the underlying zap logger. -// See Options.ZapOpts. -func RawZapOpts(zapOpts ...zap.Option) func(o *Options) { - return func(o *Options) { - o.ZapOpts = append(o.ZapOpts, zapOpts...) - } -} - -// Options contains all possible settings. -type Options struct { - // Development configures the logger to use a Zap development config - // (stacktraces on warnings, no sampling), otherwise a Zap production - // config will be used (stacktraces on errors, sampling). - Development bool - // Encoder configures how Zap will encode the output. Defaults to - // console when Development is true and JSON otherwise - Encoder zapcore.Encoder - // EncoderConfigOptions can modify the EncoderConfig needed to initialize an Encoder. - // See https://godoc.org/go.uber.org/zap/zapcore#EncoderConfig for the list of options - // that can be configured. - // Note that the EncoderConfigOptions are not applied when the Encoder option is already set. - EncoderConfigOptions []EncoderConfigOption - // NewEncoder configures Encoder using the provided EncoderConfigOptions. - // Note that the NewEncoder function is not used when the Encoder option is already set. - NewEncoder NewEncoderFunc - // DestWriter controls the destination of the log output. Defaults to - // os.Stderr. - DestWriter io.Writer - // DestWritter controls the destination of the log output. Defaults to - // os.Stderr. - // - // Deprecated: Use DestWriter instead - DestWritter io.Writer - // Level configures the verbosity of the logging. - // Defaults to Debug when Development is true and Info otherwise. - // A zap log level should be multiplied by -1 to get the logr verbosity. - // For example, to get logr verbosity of 3, set this field to zapcore.Level(-3). - // See https://pkg.go.dev/github.com/go-logr/zapr for how zap level relates to logr verbosity. - Level zapcore.LevelEnabler - // StacktraceLevel is the level at and above which stacktraces will - // be recorded for all messages. Defaults to Warn when Development - // is true and Error otherwise. - // See Level for the relationship of zap log level to logr verbosity. - StacktraceLevel zapcore.LevelEnabler - // ZapOpts allows passing arbitrary zap.Options to configure on the - // underlying Zap logger. - ZapOpts []zap.Option -} - -// addDefaults adds defaults to the Options. -func (o *Options) addDefaults() { - if o.DestWriter == nil && o.DestWritter == nil { - o.DestWriter = os.Stderr - } else if o.DestWriter == nil && o.DestWritter != nil { - // while misspelled DestWritter is deprecated but still not removed - o.DestWriter = o.DestWritter - } - - if o.Development { - if o.NewEncoder == nil { - o.NewEncoder = newConsoleEncoder - } - if o.Level == nil { - lvl := zap.NewAtomicLevelAt(zap.DebugLevel) - o.Level = &lvl - } - if o.StacktraceLevel == nil { - lvl := zap.NewAtomicLevelAt(zap.WarnLevel) - o.StacktraceLevel = &lvl - } - o.ZapOpts = append(o.ZapOpts, zap.Development()) - } else { - if o.NewEncoder == nil { - o.NewEncoder = newJSONEncoder - } - if o.Level == nil { - lvl := zap.NewAtomicLevelAt(zap.InfoLevel) - o.Level = &lvl - } - if o.StacktraceLevel == nil { - lvl := zap.NewAtomicLevelAt(zap.ErrorLevel) - o.StacktraceLevel = &lvl - } - // Disable sampling for increased Debug levels. Otherwise, this will - // cause index out of bounds errors in the sampling code. - if !o.Level.Enabled(zapcore.Level(-2)) { - o.ZapOpts = append(o.ZapOpts, - zap.WrapCore(func(core zapcore.Core) zapcore.Core { - return zapcore.NewSamplerWithOptions(core, time.Second, 100, 100) - })) - } - } - if o.Encoder == nil { - o.Encoder = o.NewEncoder(o.EncoderConfigOptions...) - } - o.ZapOpts = append(o.ZapOpts, zap.AddStacktrace(o.StacktraceLevel)) -} - -// NewRaw returns a new zap.Logger configured with the passed Opts -// or their defaults. It uses KubeAwareEncoder which adds Type -// information and Namespace/Name to the log. -func NewRaw(opts ...Opts) *zap.Logger { - o := &Options{} - for _, opt := range opts { - opt(o) - } - o.addDefaults() - - // this basically mimics NewConfig, but with a custom sink - sink := zapcore.AddSync(o.DestWriter) - - o.ZapOpts = append(o.ZapOpts, zap.AddCallerSkip(1), zap.ErrorOutput(sink)) - log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development}, sink, o.Level)) - log = log.WithOptions(o.ZapOpts...) - return log -} - -// BindFlags will parse the given flagset for zap option flags and set the log options accordingly -// zap-devel: Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn) -// Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) -// zap-encoder: Zap log encoding (one of 'json' or 'console') -// zap-log-level: Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', -// or any integer value > 0 which corresponds to custom debug levels of increasing verbosity") -// zap-stacktrace-level: Zap Level at and above which stacktraces are captured (one of 'info', 'error' or 'panic') -func (o *Options) BindFlags(fs *flag.FlagSet) { - // Set Development mode value - fs.BoolVar(&o.Development, "zap-devel", o.Development, - "Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). "+ - "Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error)") - - // Set Encoder value - var encVal encoderFlag - encVal.setFunc = func(fromFlag NewEncoderFunc) { - o.NewEncoder = fromFlag - } - fs.Var(&encVal, "zap-encoder", "Zap log encoding (one of 'json' or 'console')") - - // Set the Log Level - var levelVal levelFlag - levelVal.setFunc = func(fromFlag zapcore.LevelEnabler) { - o.Level = fromFlag - } - fs.Var(&levelVal, "zap-log-level", - "Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', "+ - "or any integer value > 0 which corresponds to custom debug levels of increasing verbosity") - - // Set the StrackTrace Level - var stackVal stackTraceFlag - stackVal.setFunc = func(fromFlag zapcore.LevelEnabler) { - o.StacktraceLevel = fromFlag - } - fs.Var(&stackVal, "zap-stacktrace-level", - "Zap Level at and above which stacktraces are captured (one of 'info', 'error', 'panic').") -} - -// UseFlagOptions configures the logger to use the Options set by parsing zap option flags from the CLI. -// opts := zap.Options{} -// opts.BindFlags(flag.CommandLine) -// flag.Parse() -// log := zap.New(zap.UseFlagOptions(&opts)) -func UseFlagOptions(in *Options) Opts { - return func(o *Options) { - *o = *in - } -}