Update go dependencies
This commit is contained in:
parent
c639f490b1
commit
d3c957192e
125 changed files with 12284 additions and 0 deletions
201
vendor/sigs.k8s.io/controller-runtime/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/controller-runtime/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
95
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
generated
vendored
Normal file
95
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2017 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 config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
)
|
||||
|
||||
var (
|
||||
kubeconfig, masterURL string
|
||||
log = logf.KBLog.WithName("client").WithName("config")
|
||||
)
|
||||
|
||||
func init() {
|
||||
// TODO: Fix this to allow double vendoring this library but still register flags on behalf of users
|
||||
flag.StringVar(&kubeconfig, "kubeconfig", "",
|
||||
"Paths to a kubeconfig. Only required if out-of-cluster.")
|
||||
|
||||
flag.StringVar(&masterURL, "master", "",
|
||||
"The address of the Kubernetes API server. Overrides any value in kubeconfig. "+
|
||||
"Only required if out-of-cluster.")
|
||||
}
|
||||
|
||||
// GetConfig creates a *rest.Config for talking to a Kubernetes apiserver.
|
||||
// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
|
||||
// in cluster and use the cluster provided kubeconfig.
|
||||
//
|
||||
// Config precedence
|
||||
//
|
||||
// * --kubeconfig flag pointing at a file
|
||||
//
|
||||
// * KUBECONFIG environment variable pointing at a file
|
||||
//
|
||||
// * In-cluster config if running in cluster
|
||||
//
|
||||
// * $HOME/.kube/config if exists
|
||||
func GetConfig() (*rest.Config, error) {
|
||||
// If a flag is specified with the config location, use that
|
||||
if len(kubeconfig) > 0 {
|
||||
return clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
|
||||
}
|
||||
// If an env variable is specified with the config locaiton, use that
|
||||
if len(os.Getenv("KUBECONFIG")) > 0 {
|
||||
return clientcmd.BuildConfigFromFlags(masterURL, os.Getenv("KUBECONFIG"))
|
||||
}
|
||||
// If no explicit location, try the in-cluster config
|
||||
if c, err := rest.InClusterConfig(); err == nil {
|
||||
return c, nil
|
||||
}
|
||||
// If no in-cluster config, try the default location in the user's home directory
|
||||
if usr, err := user.Current(); err == nil {
|
||||
if c, err := clientcmd.BuildConfigFromFlags(
|
||||
"", filepath.Join(usr.HomeDir, ".kube", "config")); err == nil {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not locate a kubeconfig")
|
||||
}
|
||||
|
||||
// GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver.
|
||||
// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
|
||||
// in cluster and use the cluster provided kubeconfig.
|
||||
//
|
||||
// Will log an error and exit if there is an error creating the rest.Config.
|
||||
func GetConfigOrDie() *rest.Config {
|
||||
config, err := GetConfig()
|
||||
if err != nil {
|
||||
log.Error(err, "unable to get kubeconfig")
|
||||
os.Exit(1)
|
||||
}
|
||||
return config
|
||||
}
|
||||
18
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go
generated
vendored
Normal file
18
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2017 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 config contains libraries for initializing rest configs for talking to the Kubernetes API
|
||||
package config
|
||||
224
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
generated
vendored
Normal file
224
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
Copyright 2018 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 envtest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// CRDInstallOptions are the options for installing CRDs
|
||||
type CRDInstallOptions struct {
|
||||
// Paths is the path to the directory containing CRDs
|
||||
Paths []string
|
||||
|
||||
// CRDs is a list of CRDs to install
|
||||
CRDs []*apiextensionsv1beta1.CustomResourceDefinition
|
||||
|
||||
// ErrorIfPathMissing will cause an error if a Path does not exist
|
||||
ErrorIfPathMissing bool
|
||||
|
||||
// maxTime is the max time to wait
|
||||
maxTime time.Duration
|
||||
|
||||
// pollInterval is the interval to check
|
||||
pollInterval time.Duration
|
||||
}
|
||||
|
||||
const defaultPollInterval = 100 * time.Millisecond
|
||||
const defaultMaxWait = 10 * time.Second
|
||||
|
||||
// InstallCRDs installs a collection of CRDs into a cluster by reading the crd yaml files from a directory
|
||||
func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]*apiextensionsv1beta1.CustomResourceDefinition, error) {
|
||||
defaultCRDOptions(&options)
|
||||
|
||||
// Read the CRD yamls into options.CRDs
|
||||
if err := readCRDFiles(&options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the CRDs in the apiserver
|
||||
if err := CreateCRDs(config, options.CRDs); err != nil {
|
||||
return options.CRDs, err
|
||||
}
|
||||
|
||||
// Wait for the CRDs to appear as Resources in the apiserver
|
||||
if err := WaitForCRDs(config, options.CRDs, options); err != nil {
|
||||
return options.CRDs, err
|
||||
}
|
||||
|
||||
return options.CRDs, nil
|
||||
}
|
||||
|
||||
// readCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs
|
||||
func readCRDFiles(options *CRDInstallOptions) error {
|
||||
if len(options.Paths) > 0 {
|
||||
for _, path := range options.Paths {
|
||||
if _, err := os.Stat(path); !options.ErrorIfPathMissing && os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
new, err := readCRDs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.CRDs = append(options.CRDs, new...)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// defaultCRDOptions sets the default values for CRDs
|
||||
func defaultCRDOptions(o *CRDInstallOptions) {
|
||||
if o.maxTime == 0 {
|
||||
o.maxTime = defaultMaxWait
|
||||
}
|
||||
if o.pollInterval == 0 {
|
||||
o.pollInterval = defaultPollInterval
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForCRDs waits for the CRDs to appear in discovery
|
||||
func WaitForCRDs(config *rest.Config, crds []*apiextensionsv1beta1.CustomResourceDefinition, options CRDInstallOptions) error {
|
||||
// Add each CRD to a map of GroupVersion to Resource
|
||||
waitingFor := map[schema.GroupVersion]*sets.String{}
|
||||
for _, crd := range crds {
|
||||
gv := schema.GroupVersion{Group: crd.Spec.Group, Version: crd.Spec.Version}
|
||||
if _, found := waitingFor[gv]; !found {
|
||||
// Initialize the set
|
||||
waitingFor[gv] = &sets.String{}
|
||||
}
|
||||
// Add the Resource
|
||||
waitingFor[gv].Insert(crd.Spec.Names.Plural)
|
||||
}
|
||||
|
||||
// Poll until all resources are found in discovery
|
||||
p := &poller{config: config, waitingFor: waitingFor}
|
||||
return wait.PollImmediate(options.pollInterval, options.maxTime, p.poll)
|
||||
}
|
||||
|
||||
// poller checks if all the resources have been found in discovery, and returns false if not
|
||||
type poller struct {
|
||||
// config is used to get discovery
|
||||
config *rest.Config
|
||||
|
||||
// waitingFor is the map of resources keyed by group version that have not yet been found in discovery
|
||||
waitingFor map[schema.GroupVersion]*sets.String
|
||||
}
|
||||
|
||||
// poll checks if all the resources have been found in discovery, and returns false if not
|
||||
func (p *poller) poll() (done bool, err error) {
|
||||
// Create a new clientset to avoid any client caching of discovery
|
||||
cs, err := clientset.NewForConfig(p.config)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
allFound := true
|
||||
for gv, resources := range p.waitingFor {
|
||||
// All resources found, do nothing
|
||||
if resources.Len() == 0 {
|
||||
delete(p.waitingFor, gv)
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the Resources for this GroupVersion
|
||||
// TODO: Maybe the controller-runtime client should be able to do this...
|
||||
resourceList, err := cs.Discovery().ServerResourcesForGroupVersion(gv.Group + "/" + gv.Version)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Remove each found resource from the resources set that we are waiting for
|
||||
for _, resource := range resourceList.APIResources {
|
||||
resources.Delete(resource.Name)
|
||||
}
|
||||
|
||||
// Still waiting on some resources in this group version
|
||||
if resources.Len() != 0 {
|
||||
allFound = false
|
||||
}
|
||||
}
|
||||
return allFound, nil
|
||||
}
|
||||
|
||||
// CreateCRDs creates the CRDs
|
||||
func CreateCRDs(config *rest.Config, crds []*apiextensionsv1beta1.CustomResourceDefinition) error {
|
||||
cs, err := clientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create each CRD
|
||||
for _, crd := range crds {
|
||||
log.V(1).Info("installing CRD", "crd", crd)
|
||||
if _, err := cs.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readCRDs reads the CRDs from files and Unmarshals them into structs
|
||||
func readCRDs(path string) ([]*apiextensionsv1beta1.CustomResourceDefinition, error) {
|
||||
// Get the CRD files
|
||||
var files []os.FileInfo
|
||||
var err error
|
||||
log.V(1).Info("reading CRDs from path", "path", path)
|
||||
if files, err = ioutil.ReadDir(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// White list the file extensions that may contain CRDs
|
||||
crdExts := sets.NewString(".json", ".yaml", ".yml")
|
||||
|
||||
var crds []*apiextensionsv1beta1.CustomResourceDefinition
|
||||
for _, file := range files {
|
||||
// Only parse whitelisted file types
|
||||
if !crdExts.Has(filepath.Ext(file.Name())) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Unmarshal the file into a struct
|
||||
b, err := ioutil.ReadFile(filepath.Join(path, file.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
crd := &apiextensionsv1beta1.CustomResourceDefinition{}
|
||||
if err = yaml.Unmarshal(b, crd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that it is actually a CRD
|
||||
if crd.Spec.Names.Kind == "" || crd.Spec.Group == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
log.V(1).Info("read CRD from file", "file", file)
|
||||
crds = append(crds, crd)
|
||||
}
|
||||
return crds, nil
|
||||
}
|
||||
18
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go
generated
vendored
Normal file
18
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2017 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 envtest provides libraries for integration testing by starting a local control plane
|
||||
package envtest
|
||||
11
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/examplecrd1.yaml
generated
vendored
Normal file
11
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/examplecrd1.yaml
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: foos.bar.example.com
|
||||
spec:
|
||||
group: bar.example.com
|
||||
names:
|
||||
kind: Foo
|
||||
plural: foos
|
||||
scope: Namespaced
|
||||
version: "v1beta1"
|
||||
11
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/examplecrd2.yaml
generated
vendored
Normal file
11
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/examplecrd2.yaml
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: bazs.qux.example.com
|
||||
spec:
|
||||
group: qux.example.com
|
||||
names:
|
||||
kind: Baz
|
||||
plural: bazs
|
||||
scope: Namespaced
|
||||
version: "v1beta1"
|
||||
11
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/ginkgo.go
generated
vendored
Normal file
11
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/ginkgo.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package envtest
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
)
|
||||
|
||||
// NewlineReporter is Reporter that Prints a newline after the default Reporter output so that the results
|
||||
// are correctly parsed by test automation.
|
||||
// See issue https://github.com/jstemmer/go-junit-report/issues/31
|
||||
// It's re-exported here to avoid compatibility breakage/mass rewrites.
|
||||
type NewlineReporter = printer.NewlineReporter
|
||||
18
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/notcrd.yaml
generated
vendored
Normal file
18
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/notcrd.yaml
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
51
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/ginkgo.go
generated
vendored
Normal file
51
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/printer/ginkgo.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2016 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 printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/ginkgo/config"
|
||||
"github.com/onsi/ginkgo/types"
|
||||
)
|
||||
|
||||
var _ ginkgo.Reporter = NewlineReporter{}
|
||||
|
||||
// NewlineReporter is Reporter that Prints a newline after the default Reporter output so that the results
|
||||
// are correctly parsed by test automation.
|
||||
// See issue https://github.com/jstemmer/go-junit-report/issues/31
|
||||
type NewlineReporter struct{}
|
||||
|
||||
// SpecSuiteWillBegin implements ginkgo.Reporter
|
||||
func (NewlineReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
|
||||
}
|
||||
|
||||
// BeforeSuiteDidRun implements ginkgo.Reporter
|
||||
func (NewlineReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {}
|
||||
|
||||
// AfterSuiteDidRun implements ginkgo.Reporter
|
||||
func (NewlineReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {}
|
||||
|
||||
// SpecWillRun implements ginkgo.Reporter
|
||||
func (NewlineReporter) SpecWillRun(specSummary *types.SpecSummary) {}
|
||||
|
||||
// SpecDidComplete implements ginkgo.Reporter
|
||||
func (NewlineReporter) SpecDidComplete(specSummary *types.SpecSummary) {}
|
||||
|
||||
// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:"
|
||||
func (NewlineReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { fmt.Printf("\n") }
|
||||
222
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go
generated
vendored
Normal file
222
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go
generated
vendored
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
Copyright 2016 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 envtest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
"sigs.k8s.io/testing_frameworks/integration"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
)
|
||||
|
||||
var log = logf.KBLog.WithName("test-env")
|
||||
|
||||
// Default binary path for test framework
|
||||
const (
|
||||
envKubeAPIServerBin = "TEST_ASSET_KUBE_APISERVER"
|
||||
envEtcdBin = "TEST_ASSET_ETCD"
|
||||
envKubectlBin = "TEST_ASSET_KUBECTL"
|
||||
envKubebuilderPath = "KUBEBUILDER_ASSETS"
|
||||
envStartTimeout = "KUBEBUILDER_CONTROLPLANE_START_TIMEOUT"
|
||||
envStopTimeout = "KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT"
|
||||
defaultKubebuilderPath = "/usr/local/kubebuilder/bin"
|
||||
StartTimeout = 60
|
||||
StopTimeout = 60
|
||||
|
||||
defaultKubebuilderControlPlaneStartTimeout = 20 * time.Second
|
||||
defaultKubebuilderControlPlaneStopTimeout = 20 * time.Second
|
||||
)
|
||||
|
||||
func defaultAssetPath(binary string) string {
|
||||
assetPath := os.Getenv(envKubebuilderPath)
|
||||
if assetPath == "" {
|
||||
assetPath = defaultKubebuilderPath
|
||||
}
|
||||
return filepath.Join(assetPath, binary)
|
||||
|
||||
}
|
||||
|
||||
// DefaultKubeAPIServerFlags are default flags necessary to bring up apiserver.
|
||||
var DefaultKubeAPIServerFlags = []string{
|
||||
"--etcd-servers={{ if .EtcdURL }}{{ .EtcdURL.String }}{{ end }}",
|
||||
"--cert-dir={{ .CertDir }}",
|
||||
"--insecure-port={{ if .URL }}{{ .URL.Port }}{{ end }}",
|
||||
"--insecure-bind-address={{ if .URL }}{{ .URL.Hostname }}{{ end }}",
|
||||
"--secure-port={{ if .SecurePort }}{{ .SecurePort }}{{ end }}",
|
||||
"--admission-control=AlwaysAdmit",
|
||||
}
|
||||
|
||||
// Environment creates a Kubernetes test environment that will start / stop the Kubernetes control plane and
|
||||
// install extension APIs
|
||||
type Environment struct {
|
||||
// ControlPlane is the ControlPlane including the apiserver and etcd
|
||||
ControlPlane integration.ControlPlane
|
||||
|
||||
// Config can be used to talk to the apiserver
|
||||
Config *rest.Config
|
||||
|
||||
// CRDs is a list of CRDs to install
|
||||
CRDs []*apiextensionsv1beta1.CustomResourceDefinition
|
||||
|
||||
// CRDDirectoryPaths is a list of paths containing CRD yaml or json configs.
|
||||
CRDDirectoryPaths []string
|
||||
|
||||
// UseExisting indicates that this environments should use an
|
||||
// existing kubeconfig, instead of trying to stand up a new control plane.
|
||||
// This is useful in cases that need aggregated API servers and the like.
|
||||
UseExistingCluster bool
|
||||
|
||||
// ControlPlaneStartTimeout is the maximum duration each controlplane component
|
||||
// may take to start. It defaults to the KUBEBUILDER_CONTROLPLANE_START_TIMEOUT
|
||||
// environment variable or 20 seconds if unspecified
|
||||
ControlPlaneStartTimeout time.Duration
|
||||
|
||||
// ControlPlaneStopTimeout is the maximum duration each controlplane component
|
||||
// may take to stop. It defaults to the KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT
|
||||
// environment variable or 20 seconds if unspecified
|
||||
ControlPlaneStopTimeout time.Duration
|
||||
|
||||
// KubeAPIServerFlags is the set of flags passed while starting the api server.
|
||||
KubeAPIServerFlags []string
|
||||
}
|
||||
|
||||
// Stop stops a running server
|
||||
func (te *Environment) Stop() error {
|
||||
if te.UseExistingCluster {
|
||||
return nil
|
||||
}
|
||||
return te.ControlPlane.Stop()
|
||||
}
|
||||
|
||||
// getAPIServerFlags returns flags to be used with the Kubernetes API server.
|
||||
func (te Environment) getAPIServerFlags() []string {
|
||||
// Set default API server flags if not set.
|
||||
if len(te.KubeAPIServerFlags) == 0 {
|
||||
return DefaultKubeAPIServerFlags
|
||||
}
|
||||
return te.KubeAPIServerFlags
|
||||
}
|
||||
|
||||
// Start starts a local Kubernetes server and updates te.ApiserverPort with the port it is listening on
|
||||
func (te *Environment) Start() (*rest.Config, error) {
|
||||
if te.UseExistingCluster {
|
||||
log.V(1).Info("using existing cluster")
|
||||
if te.Config == nil {
|
||||
// we want to allow people to pass in their own config, so
|
||||
// only load a config if it hasn't already been set.
|
||||
log.V(1).Info("automatically acquiring client configuration")
|
||||
|
||||
var err error
|
||||
te.Config, err = config.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
te.ControlPlane = integration.ControlPlane{}
|
||||
te.ControlPlane.APIServer = &integration.APIServer{Args: te.getAPIServerFlags()}
|
||||
te.ControlPlane.Etcd = &integration.Etcd{}
|
||||
|
||||
if os.Getenv(envKubeAPIServerBin) == "" {
|
||||
te.ControlPlane.APIServer.Path = defaultAssetPath("kube-apiserver")
|
||||
}
|
||||
if os.Getenv(envEtcdBin) == "" {
|
||||
te.ControlPlane.Etcd.Path = defaultAssetPath("etcd")
|
||||
}
|
||||
if os.Getenv(envKubectlBin) == "" {
|
||||
// we can't just set the path manually (it's behind a function), so set the environment variable instead
|
||||
if err := os.Setenv(envKubectlBin, defaultAssetPath("kubectl")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := te.defaultTimeouts(); err != nil {
|
||||
return nil, fmt.Errorf("failed to default controlplane timeouts: %v", err)
|
||||
}
|
||||
te.ControlPlane.Etcd.StartTimeout = te.ControlPlaneStartTimeout
|
||||
te.ControlPlane.Etcd.StopTimeout = te.ControlPlaneStopTimeout
|
||||
te.ControlPlane.APIServer.StartTimeout = te.ControlPlaneStartTimeout
|
||||
te.ControlPlane.APIServer.StopTimeout = te.ControlPlaneStopTimeout
|
||||
|
||||
log.V(1).Info("starting control plane", "api server flags", te.ControlPlane.APIServer.Args)
|
||||
if err := te.startControlPlane(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the *rest.Config for creating new clients
|
||||
te.Config = &rest.Config{
|
||||
Host: te.ControlPlane.APIURL().Host,
|
||||
}
|
||||
}
|
||||
|
||||
log.V(1).Info("installing CRDs")
|
||||
_, err := InstallCRDs(te.Config, CRDInstallOptions{
|
||||
Paths: te.CRDDirectoryPaths,
|
||||
CRDs: te.CRDs,
|
||||
})
|
||||
return te.Config, err
|
||||
}
|
||||
|
||||
func (te *Environment) startControlPlane() error {
|
||||
numTries, maxRetries := 0, 5
|
||||
var err error
|
||||
for ; numTries < maxRetries; numTries++ {
|
||||
// Start the control plane - retry if it fails
|
||||
err = te.ControlPlane.Start()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
log.Error(err, "unable to start the controlplane", "tries", numTries)
|
||||
}
|
||||
if numTries == maxRetries {
|
||||
return fmt.Errorf("failed to start the controlplane. retried %d times: %v", numTries, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *Environment) defaultTimeouts() error {
|
||||
var err error
|
||||
if te.ControlPlaneStartTimeout == 0 {
|
||||
if envVal := os.Getenv(envStartTimeout); envVal != "" {
|
||||
te.ControlPlaneStartTimeout, err = time.ParseDuration(envVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
te.ControlPlaneStartTimeout = defaultKubebuilderControlPlaneStartTimeout
|
||||
}
|
||||
}
|
||||
|
||||
if te.ControlPlaneStopTimeout == 0 {
|
||||
if envVal := os.Getenv(envStopTimeout); envVal != "" {
|
||||
te.ControlPlaneStopTimeout, err = time.ParseDuration(envVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
te.ControlPlaneStopTimeout = defaultKubebuilderControlPlaneStopTimeout
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
126
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/deleg.go
generated
vendored
Normal file
126
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/deleg.go
generated
vendored
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Copyright 2018 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 log
|
||||
|
||||
import (
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
// loggerPromise knows how to populate a concrete logr.Logger
|
||||
// with options, given an actual base logger later on down the line.
|
||||
type loggerPromise struct {
|
||||
logger *DelegatingLogger
|
||||
childPromises []*loggerPromise
|
||||
|
||||
name *string
|
||||
tags []interface{}
|
||||
}
|
||||
|
||||
// WithName provides a new Logger with the name appended
|
||||
func (p *loggerPromise) WithName(l *DelegatingLogger, name string) *loggerPromise {
|
||||
res := &loggerPromise{
|
||||
logger: l,
|
||||
name: &name,
|
||||
}
|
||||
p.childPromises = append(p.childPromises, res)
|
||||
return res
|
||||
}
|
||||
|
||||
// WithValues provides a new Logger with the tags appended
|
||||
func (p *loggerPromise) WithValues(l *DelegatingLogger, tags ...interface{}) *loggerPromise {
|
||||
res := &loggerPromise{
|
||||
logger: l,
|
||||
tags: tags,
|
||||
}
|
||||
p.childPromises = append(p.childPromises, res)
|
||||
return res
|
||||
}
|
||||
|
||||
// Fulfill instantiates the Logger with the provided logger
|
||||
func (p *loggerPromise) Fulfill(parentLogger logr.Logger) {
|
||||
var logger = parentLogger
|
||||
if p.name != nil {
|
||||
logger = logger.WithName(*p.name)
|
||||
}
|
||||
|
||||
if p.tags != nil {
|
||||
logger = logger.WithValues(p.tags...)
|
||||
}
|
||||
|
||||
p.logger.Logger = logger
|
||||
p.logger.promise = nil
|
||||
|
||||
for _, childPromise := range p.childPromises {
|
||||
childPromise.Fulfill(logger)
|
||||
}
|
||||
}
|
||||
|
||||
// DelegatingLogger is a logr.Logger that delegates to another logr.Logger.
|
||||
// If the underlying promise is not nil, it registers calls to sub-loggers with
|
||||
// the logging factory to be populated later, and returns a new delegating
|
||||
// logger. It expects to have *some* logr.Logger set at all times (generally
|
||||
// a no-op logger before the promises are fulfilled).
|
||||
type DelegatingLogger struct {
|
||||
logr.Logger
|
||||
promise *loggerPromise
|
||||
}
|
||||
|
||||
// WithName provides a new Logger with the name appended
|
||||
func (l *DelegatingLogger) WithName(name string) logr.Logger {
|
||||
if l.promise == nil {
|
||||
return l.Logger.WithName(name)
|
||||
}
|
||||
|
||||
res := &DelegatingLogger{Logger: l.Logger}
|
||||
promise := l.promise.WithName(res, name)
|
||||
res.promise = promise
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// WithValues provides a new Logger with the tags appended
|
||||
func (l *DelegatingLogger) WithValues(tags ...interface{}) logr.Logger {
|
||||
if l.promise == nil {
|
||||
return l.Logger.WithValues(tags...)
|
||||
}
|
||||
|
||||
res := &DelegatingLogger{Logger: l.Logger}
|
||||
promise := l.promise.WithValues(res, tags...)
|
||||
res.promise = promise
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Fulfill switches the logger over to use the actual logger
|
||||
// provided, instead of the temporary initial one, if this method
|
||||
// has not been previously called.
|
||||
func (l *DelegatingLogger) Fulfill(actual logr.Logger) {
|
||||
if l.promise != nil {
|
||||
l.promise.Fulfill(actual)
|
||||
}
|
||||
}
|
||||
|
||||
// NewDelegatingLogger constructs a new DelegatingLogger which uses
|
||||
// the given logger before it's promise is fulfilled.
|
||||
func NewDelegatingLogger(initial logr.Logger) *DelegatingLogger {
|
||||
l := &DelegatingLogger{
|
||||
Logger: initial,
|
||||
promise: &loggerPromise{},
|
||||
}
|
||||
l.promise.logger = l
|
||||
return l
|
||||
}
|
||||
129
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/kube_helpers.go
generated
vendored
Normal file
129
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/kube_helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Copyright 2018 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 log contains utilities for fetching a new logger
|
||||
// when one is not already available.
|
||||
package log
|
||||
|
||||
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.
|
||||
gvk := w.obj.GetObjectKind().GroupVersionKind()
|
||||
if 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)
|
||||
}
|
||||
|
||||
ns := objMeta.GetNamespace()
|
||||
if 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).
|
||||
if field.Type == zapcore.StringerType {
|
||||
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)
|
||||
}
|
||||
85
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/log.go
generated
vendored
Normal file
85
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/log.go
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright 2018 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 log contains utilities for fetching a new logger
|
||||
// when one is not already available.
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/go-logr/zapr"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// ZapLogger is a Logger implementation.
|
||||
// If development is true, a Zap development config will be used
|
||||
// (stacktraces on warnings, no sampling), otherwise a Zap production
|
||||
// config will be used (stacktraces on errors, sampling).
|
||||
func ZapLogger(development bool) logr.Logger {
|
||||
return ZapLoggerTo(os.Stderr, development)
|
||||
}
|
||||
|
||||
// ZapLoggerTo returns a new Logger implementation using Zap which logs
|
||||
// to the given destination, instead of stderr. It otherise behaves like
|
||||
// ZapLogger.
|
||||
func ZapLoggerTo(destWriter io.Writer, development bool) logr.Logger {
|
||||
// this basically mimics New<type>Config, but with a custom sink
|
||||
sink := zapcore.AddSync(destWriter)
|
||||
|
||||
var enc zapcore.Encoder
|
||||
var lvl zap.AtomicLevel
|
||||
var opts []zap.Option
|
||||
if development {
|
||||
encCfg := zap.NewDevelopmentEncoderConfig()
|
||||
enc = zapcore.NewConsoleEncoder(encCfg)
|
||||
lvl = zap.NewAtomicLevelAt(zap.DebugLevel)
|
||||
opts = append(opts, zap.Development(), zap.AddStacktrace(zap.ErrorLevel))
|
||||
} else {
|
||||
encCfg := zap.NewProductionEncoderConfig()
|
||||
enc = zapcore.NewJSONEncoder(encCfg)
|
||||
lvl = zap.NewAtomicLevelAt(zap.InfoLevel)
|
||||
opts = append(opts, zap.AddStacktrace(zap.WarnLevel),
|
||||
zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
||||
return zapcore.NewSampler(core, time.Second, 100, 100)
|
||||
}))
|
||||
}
|
||||
opts = append(opts, zap.AddCallerSkip(1), zap.ErrorOutput(sink))
|
||||
log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: enc, Verbose: development}, sink, lvl))
|
||||
log = log.WithOptions(opts...)
|
||||
return zapr.NewLogger(log)
|
||||
}
|
||||
|
||||
// SetLogger sets a concrete logging implementation for all deferred Loggers.
|
||||
func SetLogger(l logr.Logger) {
|
||||
Log.Fulfill(l)
|
||||
}
|
||||
|
||||
// Log is the base logger used by kubebuilder. It delegates
|
||||
// to another logr.Logger. You *must* call SetLogger to
|
||||
// get any actual logging.
|
||||
var Log = NewDelegatingLogger(NullLogger{})
|
||||
|
||||
// KBLog is a base parent logger.
|
||||
var KBLog logr.Logger
|
||||
|
||||
func init() {
|
||||
KBLog = Log.WithName("kubebuilder")
|
||||
}
|
||||
60
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/null.go
generated
vendored
Normal file
60
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/log/null.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Copyright 2018 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 log
|
||||
|
||||
import (
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
// NB: this is the same as the null logger logr/testing,
|
||||
// but avoids accidentally adding the testing flags to
|
||||
// all binaries.
|
||||
|
||||
// NullLogger is a logr.Logger that does nothing.
|
||||
type NullLogger struct{}
|
||||
|
||||
var _ logr.Logger = NullLogger{}
|
||||
|
||||
// Info implements logr.InfoLogger
|
||||
func (NullLogger) Info(_ string, _ ...interface{}) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
// Enabled implements logr.InfoLogger
|
||||
func (NullLogger) Enabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Error implements logr.Logger
|
||||
func (NullLogger) Error(_ error, _ string, _ ...interface{}) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
// V implements logr.Logger
|
||||
func (log NullLogger) V(_ int) logr.InfoLogger {
|
||||
return log
|
||||
}
|
||||
|
||||
// WithName implements logr.Logger
|
||||
func (log NullLogger) WithName(_ string) logr.Logger {
|
||||
return log
|
||||
}
|
||||
|
||||
// WithValues implements logr.Logger
|
||||
func (log NullLogger) WithValues(_ ...interface{}) logr.Logger {
|
||||
return log
|
||||
}
|
||||
201
vendor/sigs.k8s.io/testing_frameworks/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/testing_frameworks/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 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.
|
||||
1
vendor/sigs.k8s.io/testing_frameworks/integration/.gitignore
generated
vendored
Normal file
1
vendor/sigs.k8s.io/testing_frameworks/integration/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
assets/bin
|
||||
8
vendor/sigs.k8s.io/testing_frameworks/integration/README.md
generated
vendored
Normal file
8
vendor/sigs.k8s.io/testing_frameworks/integration/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Integration Testing Framework
|
||||
|
||||
A framework for integration testing components of kubernetes. This framework is
|
||||
intended to work properly both in CI, and on a local dev machine. It therefore
|
||||
explicitly supports both Linux and Darwin.
|
||||
|
||||
For detailed documentation see the
|
||||
[](https://godoc.org/github.com/kubernetes-sigs/testing_frameworks/integration).
|
||||
24
vendor/sigs.k8s.io/testing_frameworks/integration/addr/manager.go
generated
vendored
Normal file
24
vendor/sigs.k8s.io/testing_frameworks/integration/addr/manager.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package addr
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// Suggest suggests a address a process can listen on. It returns
|
||||
// a tuple consisting of a free port and the hostname resolved to its IP.
|
||||
func Suggest() (port int, resolvedHost string, err error) {
|
||||
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
l, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
port = l.Addr().(*net.TCPAddr).Port
|
||||
defer func() {
|
||||
err = l.Close()
|
||||
}()
|
||||
resolvedHost = addr.IP.String()
|
||||
return
|
||||
}
|
||||
131
vendor/sigs.k8s.io/testing_frameworks/integration/apiserver.go
generated
vendored
Normal file
131
vendor/sigs.k8s.io/testing_frameworks/integration/apiserver.go
generated
vendored
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/testing_frameworks/integration/addr"
|
||||
"sigs.k8s.io/testing_frameworks/integration/internal"
|
||||
)
|
||||
|
||||
// APIServer knows how to run a kubernetes apiserver.
|
||||
type APIServer struct {
|
||||
// URL is the address the ApiServer should listen on for client connections.
|
||||
//
|
||||
// If this is not specified, we default to a random free port on localhost.
|
||||
URL *url.URL
|
||||
|
||||
// SecurePort is the additional secure port that the APIServer should listen on.
|
||||
SecurePort int
|
||||
|
||||
// Path is the path to the apiserver binary.
|
||||
//
|
||||
// If this is left as the empty string, we will attempt to locate a binary,
|
||||
// by checking for the TEST_ASSET_KUBE_APISERVER environment variable, and
|
||||
// the default test assets directory. See the "Binaries" section above (in
|
||||
// doc.go) for details.
|
||||
Path string
|
||||
|
||||
// Args is a list of arguments which will passed to the APIServer binary.
|
||||
// Before they are passed on, they will be evaluated as go-template strings.
|
||||
// This means you can use fields which are defined and exported on this
|
||||
// APIServer struct (e.g. "--cert-dir={{ .Dir }}").
|
||||
// Those templates will be evaluated after the defaulting of the APIServer's
|
||||
// fields has already happened and just before the binary actually gets
|
||||
// started. Thus you have access to caluclated fields like `URL` and others.
|
||||
//
|
||||
// If not specified, the minimal set of arguments to run the APIServer will
|
||||
// be used.
|
||||
Args []string
|
||||
|
||||
// CertDir is a path to a directory containing whatever certificates the
|
||||
// APIServer will need.
|
||||
//
|
||||
// If left unspecified, then the Start() method will create a fresh temporary
|
||||
// directory, and the Stop() method will clean it up.
|
||||
CertDir string
|
||||
|
||||
// EtcdURL is the URL of the Etcd the APIServer should use.
|
||||
//
|
||||
// If this is not specified, the Start() method will return an error.
|
||||
EtcdURL *url.URL
|
||||
|
||||
// StartTimeout, StopTimeout specify the time the APIServer is allowed to
|
||||
// take when starting and stoppping before an error is emitted.
|
||||
//
|
||||
// If not specified, these default to 20 seconds.
|
||||
StartTimeout time.Duration
|
||||
StopTimeout time.Duration
|
||||
|
||||
// Out, Err specify where APIServer should write its StdOut, StdErr to.
|
||||
//
|
||||
// If not specified, the output will be discarded.
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
|
||||
processState *internal.ProcessState
|
||||
}
|
||||
|
||||
// Start starts the apiserver, waits for it to come up, and returns an error,
|
||||
// if occurred.
|
||||
func (s *APIServer) Start() error {
|
||||
if s.EtcdURL == nil {
|
||||
return fmt.Errorf("expected EtcdURL to be configured")
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
s.processState = &internal.ProcessState{}
|
||||
|
||||
s.processState.DefaultedProcessInput, err = internal.DoDefaulting(
|
||||
"kube-apiserver",
|
||||
s.URL,
|
||||
s.CertDir,
|
||||
s.Path,
|
||||
s.StartTimeout,
|
||||
s.StopTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Defaulting the secure port
|
||||
if s.SecurePort == 0 {
|
||||
s.SecurePort, _, err = addr.Suggest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.processState.HealthCheckEndpoint = "/healthz"
|
||||
|
||||
s.URL = &s.processState.URL
|
||||
s.CertDir = s.processState.Dir
|
||||
s.Path = s.processState.Path
|
||||
s.StartTimeout = s.processState.StartTimeout
|
||||
s.StopTimeout = s.processState.StopTimeout
|
||||
|
||||
s.processState.Args, err = internal.RenderTemplates(
|
||||
internal.DoAPIServerArgDefaulting(s.Args), s,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.processState.Start(s.Out, s.Err)
|
||||
}
|
||||
|
||||
// Stop stops this process gracefully, waits for its termination, and cleans up
|
||||
// the CertDir if necessary.
|
||||
func (s *APIServer) Stop() error {
|
||||
return s.processState.Stop()
|
||||
}
|
||||
|
||||
// APIServerDefaultArgs exposes the default args for the APIServer so that you
|
||||
// can use those to append your own additional arguments.
|
||||
//
|
||||
// The internal default arguments are explicitely copied here, we don't want to
|
||||
// allow users to change the internal ones.
|
||||
var APIServerDefaultArgs = append([]string{}, internal.APIServerDefaultArgs...)
|
||||
59
vendor/sigs.k8s.io/testing_frameworks/integration/control_plane.go
generated
vendored
Normal file
59
vendor/sigs.k8s.io/testing_frameworks/integration/control_plane.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ControlPlane is a struct that knows how to start your test control plane.
|
||||
//
|
||||
// Right now, that means Etcd and your APIServer. This is likely to increase in
|
||||
// future.
|
||||
type ControlPlane struct {
|
||||
APIServer *APIServer
|
||||
Etcd *Etcd
|
||||
}
|
||||
|
||||
// Start will start your control plane processes. To stop them, call Stop().
|
||||
func (f *ControlPlane) Start() error {
|
||||
if f.Etcd == nil {
|
||||
f.Etcd = &Etcd{}
|
||||
}
|
||||
if err := f.Etcd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.APIServer == nil {
|
||||
f.APIServer = &APIServer{}
|
||||
}
|
||||
f.APIServer.EtcdURL = f.Etcd.URL
|
||||
return f.APIServer.Start()
|
||||
}
|
||||
|
||||
// Stop will stop your control plane processes, and clean up their data.
|
||||
func (f *ControlPlane) Stop() error {
|
||||
if f.APIServer != nil {
|
||||
if err := f.APIServer.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if f.Etcd != nil {
|
||||
if err := f.Etcd.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// APIURL returns the URL you should connect to to talk to your API.
|
||||
func (f *ControlPlane) APIURL() *url.URL {
|
||||
return f.APIServer.URL
|
||||
}
|
||||
|
||||
// KubeCtl returns a pre-configured KubeCtl, ready to connect to this
|
||||
// ControlPlane.
|
||||
func (f *ControlPlane) KubeCtl() *KubeCtl {
|
||||
k := &KubeCtl{}
|
||||
k.Opts = append(k.Opts, fmt.Sprintf("--server=%s", f.APIURL()))
|
||||
return k
|
||||
}
|
||||
119
vendor/sigs.k8s.io/testing_frameworks/integration/doc.go
generated
vendored
Normal file
119
vendor/sigs.k8s.io/testing_frameworks/integration/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
|
||||
Package integration implements an integration testing framework for kubernetes.
|
||||
|
||||
It provides components for standing up a kubernetes API, against which you can test a
|
||||
kubernetes client, or other kubernetes components. The lifecycle of the components
|
||||
needed to provide this API is managed by this framework.
|
||||
|
||||
Quickstart
|
||||
|
||||
If you want to test a kubernetes client against the latest kubernetes APIServer
|
||||
and Etcd, you can use `./scripts/download-binaries.sh` to download APIServer
|
||||
and Etcd binaries for your platform. Then add something like the following to
|
||||
your tests:
|
||||
|
||||
cp := &integration.ControlPlane{}
|
||||
cp.Start()
|
||||
kubeCtl := cp.KubeCtl()
|
||||
stdout, stderr, err := kubeCtl.Run("get", "pods")
|
||||
// You can check on err, stdout & stderr and build up
|
||||
// your tests
|
||||
cp.Stop()
|
||||
|
||||
Components
|
||||
|
||||
Currently the framework provides the following components:
|
||||
|
||||
ControlPlane: The ControlPlane wraps Etcd & APIServer (see below) and wires
|
||||
them together correctly. A ControlPlane can be stopped & started and can
|
||||
provide the URL to connect to the API. The ControlPlane can also be asked for a
|
||||
KubeCtl which is already correctly configured for this ControlPlane. The
|
||||
ControlPlane is a good entry point for default setups.
|
||||
|
||||
Etcd: Manages an Etcd binary, which can be started, stopped and connected to.
|
||||
By default Etcd will listen on a random port for http connections and will
|
||||
create a temporary directory for its data. To configure it differently, see the
|
||||
Etcd type documentation below.
|
||||
|
||||
APIServer: Manages an Kube-APIServer binary, which can be started, stopped and
|
||||
connected to. By default APIServer will listen on a random port for http
|
||||
connections and will create a temporary directory to store the (auto-generated)
|
||||
certificates. To configure it differently, see the APIServer type
|
||||
documentation below.
|
||||
|
||||
KubeCtl: Wraps around a `kubectl` binary and can `Run(...)` arbitrary commands
|
||||
against a kubernetes control plane.
|
||||
|
||||
Binaries
|
||||
|
||||
Etcd, APIServer & KubeCtl use the same mechanism to determine which binaries to
|
||||
use when they get started.
|
||||
|
||||
1. If the component is configured with a `Path` the framework tries to run that
|
||||
binary.
|
||||
For example:
|
||||
|
||||
myEtcd := &Etcd{
|
||||
Path: "/some/other/etcd",
|
||||
}
|
||||
cp := &integration.ControlPlane{
|
||||
Etcd: myEtcd,
|
||||
}
|
||||
cp.Start()
|
||||
|
||||
2. If the Path field on APIServer, Etcd or KubeCtl is left unset and an
|
||||
environment variable named `TEST_ASSET_KUBE_APISERVER`, `TEST_ASSET_ETCD` or
|
||||
`TEST_ASSET_KUBECTL` is set, its value is used as a path to the binary for the
|
||||
APIServer, Etcd or KubeCtl.
|
||||
|
||||
3. If neither the `Path` field, nor the environment variable is set, the
|
||||
framework tries to use the binaries `kube-apiserver`, `etcd` or `kubectl` in
|
||||
the directory `${FRAMEWORK_DIR}/assets/bin/`.
|
||||
|
||||
For convenience this framework ships with
|
||||
`${FRAMEWORK_DIR}/scripts/download-binaries.sh` which can be used to download
|
||||
pre-compiled versions of the needed binaries and place them in the default
|
||||
location (`${FRAMEWORK_DIR}/assets/bin/`).
|
||||
|
||||
Arguments for Etcd and APIServer
|
||||
|
||||
Those components will start without any configuration. However, if you want or
|
||||
need to, you can override certain configuration -- one of which are the
|
||||
arguments used when calling the binary.
|
||||
|
||||
When you choose to specify your own set of arguments, those won't be appended
|
||||
to the default set of arguments, it is your responsibility to provide all the
|
||||
arguments needed for the binary to start successfully.
|
||||
|
||||
However, the default arguments for APIServer and Etcd are exported as
|
||||
`APIServerDefaultArgs` and `EtcdDefaultArgs` from this package. Treat those
|
||||
variables as read-only constants. Internally we have a set of default
|
||||
arguments for defaulting, the `APIServerDefaultArgs` and `EtcdDefaultArgs` are
|
||||
just copies of those. So when you override them you loose access to the actual
|
||||
internal default arguments, but your override won't affect the defaulting.
|
||||
|
||||
All arguments are interpreted as go templates. Those templates have access to
|
||||
all exported fields of the `APIServer`/`Etcd` struct. It does not matter if
|
||||
those fields where explicitly set up or if they were defaulted by calling the
|
||||
`Start()` method, the template evaluation runs just before the binary is
|
||||
executed and right after the defaulting of all the struct's fields has
|
||||
happened.
|
||||
|
||||
// When you want to append additional arguments ...
|
||||
etcd := &Etcd{
|
||||
// Additional custom arguments will appended to the set of default
|
||||
// arguments
|
||||
Args: append(EtcdDefaultArgs, "--additional=arg"),
|
||||
DataDir: "/my/special/data/dir",
|
||||
}
|
||||
|
||||
// When you want to use a custom set of arguments ...
|
||||
etcd := &Etcd{
|
||||
// Only custom arguments will be passed to the binary
|
||||
Args: []string{"--one=1", "--two=2", "--three=3"},
|
||||
DataDir: "/my/special/data/dir",
|
||||
}
|
||||
|
||||
*/
|
||||
package integration
|
||||
109
vendor/sigs.k8s.io/testing_frameworks/integration/etcd.go
generated
vendored
Normal file
109
vendor/sigs.k8s.io/testing_frameworks/integration/etcd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"net/url"
|
||||
|
||||
"sigs.k8s.io/testing_frameworks/integration/internal"
|
||||
)
|
||||
|
||||
// Etcd knows how to run an etcd server.
|
||||
type Etcd struct {
|
||||
// URL is the address the Etcd should listen on for client connections.
|
||||
//
|
||||
// If this is not specified, we default to a random free port on localhost.
|
||||
URL *url.URL
|
||||
|
||||
// Path is the path to the etcd binary.
|
||||
//
|
||||
// If this is left as the empty string, we will attempt to locate a binary,
|
||||
// by checking for the TEST_ASSET_ETCD environment variable, and the default
|
||||
// test assets directory. See the "Binaries" section above (in doc.go) for
|
||||
// details.
|
||||
Path string
|
||||
|
||||
// Args is a list of arguments which will passed to the Etcd binary. Before
|
||||
// they are passed on, the`y will be evaluated as go-template strings. This
|
||||
// means you can use fields which are defined and exported on this Etcd
|
||||
// struct (e.g. "--data-dir={{ .Dir }}").
|
||||
// Those templates will be evaluated after the defaulting of the Etcd's
|
||||
// fields has already happened and just before the binary actually gets
|
||||
// started. Thus you have access to caluclated fields like `URL` and others.
|
||||
//
|
||||
// If not specified, the minimal set of arguments to run the Etcd will be
|
||||
// used.
|
||||
Args []string
|
||||
|
||||
// DataDir is a path to a directory in which etcd can store its state.
|
||||
//
|
||||
// If left unspecified, then the Start() method will create a fresh temporary
|
||||
// directory, and the Stop() method will clean it up.
|
||||
DataDir string
|
||||
|
||||
// StartTimeout, StopTimeout specify the time the Etcd is allowed to
|
||||
// take when starting and stopping before an error is emitted.
|
||||
//
|
||||
// If not specified, these default to 20 seconds.
|
||||
StartTimeout time.Duration
|
||||
StopTimeout time.Duration
|
||||
|
||||
// Out, Err specify where Etcd should write its StdOut, StdErr to.
|
||||
//
|
||||
// If not specified, the output will be discarded.
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
|
||||
processState *internal.ProcessState
|
||||
}
|
||||
|
||||
// Start starts the etcd, waits for it to come up, and returns an error, if one
|
||||
// occoured.
|
||||
func (e *Etcd) Start() error {
|
||||
var err error
|
||||
|
||||
e.processState = &internal.ProcessState{}
|
||||
|
||||
e.processState.DefaultedProcessInput, err = internal.DoDefaulting(
|
||||
"etcd",
|
||||
e.URL,
|
||||
e.DataDir,
|
||||
e.Path,
|
||||
e.StartTimeout,
|
||||
e.StopTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.processState.StartMessage = internal.GetEtcdStartMessage(e.processState.URL)
|
||||
|
||||
e.URL = &e.processState.URL
|
||||
e.DataDir = e.processState.Dir
|
||||
e.Path = e.processState.Path
|
||||
e.StartTimeout = e.processState.StartTimeout
|
||||
e.StopTimeout = e.processState.StopTimeout
|
||||
|
||||
e.processState.Args, err = internal.RenderTemplates(
|
||||
internal.DoEtcdArgDefaulting(e.Args), e,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.processState.Start(e.Out, e.Err)
|
||||
}
|
||||
|
||||
// Stop stops this process gracefully, waits for its termination, and cleans up
|
||||
// the DataDir if necessary.
|
||||
func (e *Etcd) Stop() error {
|
||||
return e.processState.Stop()
|
||||
}
|
||||
|
||||
// EtcdDefaultArgs exposes the default args for Etcd so that you
|
||||
// can use those to append your own additional arguments.
|
||||
//
|
||||
// The internal default arguments are explicitely copied here, we don't want to
|
||||
// allow users to change the internal ones.
|
||||
var EtcdDefaultArgs = append([]string{}, internal.EtcdDefaultArgs...)
|
||||
17
vendor/sigs.k8s.io/testing_frameworks/integration/internal/apiserver.go
generated
vendored
Normal file
17
vendor/sigs.k8s.io/testing_frameworks/integration/internal/apiserver.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package internal
|
||||
|
||||
var APIServerDefaultArgs = []string{
|
||||
"--etcd-servers={{ if .EtcdURL }}{{ .EtcdURL.String }}{{ end }}",
|
||||
"--cert-dir={{ .CertDir }}",
|
||||
"--insecure-port={{ if .URL }}{{ .URL.Port }}{{ end }}",
|
||||
"--insecure-bind-address={{ if .URL }}{{ .URL.Hostname }}{{ end }}",
|
||||
"--secure-port={{ if .SecurePort }}{{ .SecurePort }}{{ end }}",
|
||||
}
|
||||
|
||||
func DoAPIServerArgDefaulting(args []string) []string {
|
||||
if len(args) != 0 {
|
||||
return args
|
||||
}
|
||||
|
||||
return APIServerDefaultArgs
|
||||
}
|
||||
28
vendor/sigs.k8s.io/testing_frameworks/integration/internal/arguments.go
generated
vendored
Normal file
28
vendor/sigs.k8s.io/testing_frameworks/integration/internal/arguments.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
func RenderTemplates(argTemplates []string, data interface{}) (args []string, err error) {
|
||||
var t *template.Template
|
||||
|
||||
for _, arg := range argTemplates {
|
||||
t, err = template.New(arg).Parse(arg)
|
||||
if err != nil {
|
||||
args = nil
|
||||
return
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err = t.Execute(buf, data)
|
||||
if err != nil {
|
||||
args = nil
|
||||
return
|
||||
}
|
||||
args = append(args, buf.String())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
35
vendor/sigs.k8s.io/testing_frameworks/integration/internal/bin_path_finder.go
generated
vendored
Normal file
35
vendor/sigs.k8s.io/testing_frameworks/integration/internal/bin_path_finder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var assetsPath string
|
||||
|
||||
func init() {
|
||||
_, thisFile, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
panic("Could not determine the path of the BinPathFinder")
|
||||
}
|
||||
assetsPath = filepath.Join(filepath.Dir(thisFile), "..", "assets", "bin")
|
||||
}
|
||||
|
||||
// BinPathFinder checks the an environment variable, derived from the symbolic name,
|
||||
// and falls back to a default assets location when this variable is not set
|
||||
func BinPathFinder(symbolicName string) (binPath string) {
|
||||
punctuationPattern := regexp.MustCompile("[^A-Z0-9]+")
|
||||
sanitizedName := punctuationPattern.ReplaceAllString(strings.ToUpper(symbolicName), "_")
|
||||
leadingNumberPattern := regexp.MustCompile("^[0-9]+")
|
||||
sanitizedName = leadingNumberPattern.ReplaceAllString(sanitizedName, "")
|
||||
envVar := "TEST_ASSET_" + sanitizedName
|
||||
|
||||
if val, ok := os.LookupEnv(envVar); ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return filepath.Join(assetsPath, symbolicName)
|
||||
}
|
||||
36
vendor/sigs.k8s.io/testing_frameworks/integration/internal/etcd.go
generated
vendored
Normal file
36
vendor/sigs.k8s.io/testing_frameworks/integration/internal/etcd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package internal
|
||||
|
||||
import "net/url"
|
||||
|
||||
var EtcdDefaultArgs = []string{
|
||||
"--listen-peer-urls=http://localhost:0",
|
||||
"--advertise-client-urls={{ if .URL }}{{ .URL.String }}{{ end }}",
|
||||
"--listen-client-urls={{ if .URL }}{{ .URL.String }}{{ end }}",
|
||||
"--data-dir={{ .DataDir }}",
|
||||
}
|
||||
|
||||
func DoEtcdArgDefaulting(args []string) []string {
|
||||
if len(args) != 0 {
|
||||
return args
|
||||
}
|
||||
|
||||
return EtcdDefaultArgs
|
||||
}
|
||||
|
||||
func isSecureScheme(scheme string) bool {
|
||||
// https://github.com/coreos/etcd/blob/d9deeff49a080a88c982d328ad9d33f26d1ad7b6/pkg/transport/listener.go#L53
|
||||
if scheme == "https" || scheme == "unixs" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetEtcdStartMessage(listenUrl url.URL) string {
|
||||
if isSecureScheme(listenUrl.Scheme) {
|
||||
// https://github.com/coreos/etcd/blob/a7f1fbe00ec216fcb3a1919397a103b41dca8413/embed/serve.go#L167
|
||||
return "serving client requests on " + listenUrl.Hostname()
|
||||
}
|
||||
|
||||
// https://github.com/coreos/etcd/blob/a7f1fbe00ec216fcb3a1919397a103b41dca8413/embed/serve.go#L124
|
||||
return "serving insecure client requests on " + listenUrl.Hostname()
|
||||
}
|
||||
203
vendor/sigs.k8s.io/testing_frameworks/integration/internal/process.go
generated
vendored
Normal file
203
vendor/sigs.k8s.io/testing_frameworks/integration/internal/process.go
generated
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/gomega/gbytes"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
|
||||
"sigs.k8s.io/testing_frameworks/integration/addr"
|
||||
)
|
||||
|
||||
type ProcessState struct {
|
||||
DefaultedProcessInput
|
||||
Session *gexec.Session
|
||||
// Healthcheck Endpoint. If we get http.StatusOK from this endpoint, we
|
||||
// assume the process is ready to operate. E.g. "/healthz". If this is set,
|
||||
// we ignore StartMessage.
|
||||
HealthCheckEndpoint string
|
||||
// HealthCheckPollInterval is the interval which will be used for polling the
|
||||
// HealthCheckEndpoint.
|
||||
// If left empty it will default to 100 Milliseconds.
|
||||
HealthCheckPollInterval time.Duration
|
||||
// StartMessage is the message to wait for on stderr. If we recieve this
|
||||
// message, we assume the process is ready to operate. Ignored if
|
||||
// HealthCheckEndpoint is specified.
|
||||
//
|
||||
// The usage of StartMessage is discouraged, favour HealthCheckEndpoint
|
||||
// instead!
|
||||
//
|
||||
// Deprecated: Use HealthCheckEndpoint in favour of StartMessage
|
||||
StartMessage string
|
||||
Args []string
|
||||
}
|
||||
|
||||
type DefaultedProcessInput struct {
|
||||
URL url.URL
|
||||
Dir string
|
||||
DirNeedsCleaning bool
|
||||
Path string
|
||||
StopTimeout time.Duration
|
||||
StartTimeout time.Duration
|
||||
}
|
||||
|
||||
func DoDefaulting(
|
||||
name string,
|
||||
listenUrl *url.URL,
|
||||
dir string,
|
||||
path string,
|
||||
startTimeout time.Duration,
|
||||
stopTimeout time.Duration,
|
||||
) (DefaultedProcessInput, error) {
|
||||
defaults := DefaultedProcessInput{
|
||||
Dir: dir,
|
||||
Path: path,
|
||||
StartTimeout: startTimeout,
|
||||
StopTimeout: stopTimeout,
|
||||
}
|
||||
|
||||
if listenUrl == nil {
|
||||
port, host, err := addr.Suggest()
|
||||
if err != nil {
|
||||
return DefaultedProcessInput{}, err
|
||||
}
|
||||
defaults.URL = url.URL{
|
||||
Scheme: "http",
|
||||
Host: fmt.Sprintf("%s:%d", host, port),
|
||||
}
|
||||
} else {
|
||||
defaults.URL = *listenUrl
|
||||
}
|
||||
|
||||
if dir == "" {
|
||||
newDir, err := ioutil.TempDir("", "k8s_test_framework_")
|
||||
if err != nil {
|
||||
return DefaultedProcessInput{}, err
|
||||
}
|
||||
defaults.Dir = newDir
|
||||
defaults.DirNeedsCleaning = true
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
if name == "" {
|
||||
return DefaultedProcessInput{}, fmt.Errorf("must have at least one of name or path")
|
||||
}
|
||||
defaults.Path = BinPathFinder(name)
|
||||
}
|
||||
|
||||
if startTimeout == 0 {
|
||||
defaults.StartTimeout = 20 * time.Second
|
||||
}
|
||||
|
||||
if stopTimeout == 0 {
|
||||
defaults.StopTimeout = 20 * time.Second
|
||||
}
|
||||
|
||||
return defaults, nil
|
||||
}
|
||||
|
||||
type stopChannel chan struct{}
|
||||
|
||||
func (ps *ProcessState) Start(stdout, stderr io.Writer) (err error) {
|
||||
command := exec.Command(ps.Path, ps.Args...)
|
||||
|
||||
ready := make(chan bool)
|
||||
timedOut := time.After(ps.StartTimeout)
|
||||
var pollerStopCh stopChannel
|
||||
|
||||
if ps.HealthCheckEndpoint != "" {
|
||||
healthCheckURL := ps.URL
|
||||
healthCheckURL.Path = ps.HealthCheckEndpoint
|
||||
pollerStopCh = make(stopChannel)
|
||||
go pollURLUntilOK(healthCheckURL, ps.HealthCheckPollInterval, ready, pollerStopCh)
|
||||
} else {
|
||||
startDetectStream := gbytes.NewBuffer()
|
||||
ready = startDetectStream.Detect(ps.StartMessage)
|
||||
stderr = safeMultiWriter(stderr, startDetectStream)
|
||||
}
|
||||
|
||||
ps.Session, err = gexec.Start(command, stdout, stderr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ready:
|
||||
return nil
|
||||
case <-timedOut:
|
||||
if pollerStopCh != nil {
|
||||
close(pollerStopCh)
|
||||
}
|
||||
if ps.Session != nil {
|
||||
ps.Session.Terminate()
|
||||
}
|
||||
return fmt.Errorf("timeout waiting for process %s to start", path.Base(ps.Path))
|
||||
}
|
||||
}
|
||||
|
||||
func safeMultiWriter(writers ...io.Writer) io.Writer {
|
||||
safeWriters := []io.Writer{}
|
||||
for _, w := range writers {
|
||||
if w != nil {
|
||||
safeWriters = append(safeWriters, w)
|
||||
}
|
||||
}
|
||||
return io.MultiWriter(safeWriters...)
|
||||
}
|
||||
|
||||
func pollURLUntilOK(url url.URL, interval time.Duration, ready chan bool, stopCh stopChannel) {
|
||||
if interval <= 0 {
|
||||
interval = 100 * time.Millisecond
|
||||
}
|
||||
for {
|
||||
res, err := http.Get(url.String())
|
||||
if err == nil && res.StatusCode == http.StatusOK {
|
||||
ready <- true
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
default:
|
||||
time.Sleep(interval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *ProcessState) Stop() error {
|
||||
if ps.Session == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// gexec's Session methods (Signal, Kill, ...) do not check if the Process is
|
||||
// nil, so we are doing this here for now.
|
||||
// This should probably be fixed in gexec.
|
||||
if ps.Session.Command.Process == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
detectedStop := ps.Session.Terminate().Exited
|
||||
timedOut := time.After(ps.StopTimeout)
|
||||
|
||||
select {
|
||||
case <-detectedStop:
|
||||
break
|
||||
case <-timedOut:
|
||||
return fmt.Errorf("timeout waiting for process %s to stop", path.Base(ps.Path))
|
||||
}
|
||||
|
||||
if ps.DirNeedsCleaning {
|
||||
return os.RemoveAll(ps.Dir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
47
vendor/sigs.k8s.io/testing_frameworks/integration/kubectl.go
generated
vendored
Normal file
47
vendor/sigs.k8s.io/testing_frameworks/integration/kubectl.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os/exec"
|
||||
|
||||
"sigs.k8s.io/testing_frameworks/integration/internal"
|
||||
)
|
||||
|
||||
// KubeCtl is a wrapper around the kubectl binary.
|
||||
type KubeCtl struct {
|
||||
// Path where the kubectl binary can be found.
|
||||
//
|
||||
// If this is left empty, we will attempt to locate a binary, by checking for
|
||||
// the TEST_ASSET_KUBECTL environment variable, and the default test assets
|
||||
// directory. See the "Binaries" section above (in doc.go) for details.
|
||||
Path string
|
||||
|
||||
// Opts can be used to configure additional flags which will be used each
|
||||
// time the wrapped binary is called.
|
||||
//
|
||||
// For example, you might want to use this to set the URL of the APIServer to
|
||||
// connect to.
|
||||
Opts []string
|
||||
}
|
||||
|
||||
// Run executes the wrapped binary with some preconfigured options and the
|
||||
// arguments given to this method. It returns Readers for the stdout and
|
||||
// stderr.
|
||||
func (k *KubeCtl) Run(args ...string) (stdout, stderr io.Reader, err error) {
|
||||
if k.Path == "" {
|
||||
k.Path = internal.BinPathFinder("kubectl")
|
||||
}
|
||||
|
||||
stdoutBuffer := &bytes.Buffer{}
|
||||
stderrBuffer := &bytes.Buffer{}
|
||||
allArgs := append(k.Opts, args...)
|
||||
|
||||
cmd := exec.Command(k.Path, allArgs...)
|
||||
cmd.Stdout = stdoutBuffer
|
||||
cmd.Stderr = stderrBuffer
|
||||
|
||||
err = cmd.Run()
|
||||
|
||||
return stdoutBuffer, stderrBuffer, err
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue